sql - 如何在没有临时表的情况下使用 SQL 游标跳过一行
问题描述
我在 SQL 中有一个包含以下列的大表:
公司 ID(整数) | 电子邮件(Varchar 255) | 名字(Varchar 50) | 姓氏(Varchar 50) |
---|---|---|---|
1 | jim_halpert@dundermifflin.com | 吉姆 | 哈尔珀特 |
2 | bvance@vancerefridgerations.com | 鲍勃 | 万斯 |
1 | michael_scott@dundermifflin.com | 迈克尔 | 斯科特 |
CompanyId 可以重复多次,因为公司附加到各种电子邮件中。
我的雇主希望我找到属于特定类型的公司电子邮件。在几个 IF 语句之后,最终结果将打印如下消息:
“CompanyId”具有 firstName_lastName@companyName.domain 类型的电子邮件
“CompanyId”具有 firstInitial_lastName@companyName.domain 类型的电子邮件
我的雇主告诉我使用光标找到我的解决方案,但是一旦我启动光标,我需要检查 CompanyId 以查看该 id 是否已经被循环并找到了类型。如果 CompanyId 已经经历了这个循环,我想跳过它。
到目前为止,这是我的代码
DECLARE @CoId INT
,@Email VARCHAR(255)
,@FName varchar(50)
,@LName varchar(50)
Declare @condition bit = 1
Declare CoCursor CURSOR
For SELECT E.CompanyID, E.Email, P.First_Name, P.Last_Name
From Table_Email as E
Left Join Table_People as P
ON E.EmployeeID = P.EmployeeID
Order by CompanyID, Email
-- Loop through the rows with Cursors for CompanyId and Email
OPEN CoCursor
Fetch NEXT FROM CoCursor
INTO @CoId, @Email, @FName, @LName
While @@FETCH_STATUS = 0
BEGIN
-- Check to see if CompanyId has been logged before, if not, proceed
-- Check to see if email matches criteria
IF @Email LIKE @FName + '[_]' + @LName + '@%'
BEGIN
-- If yes, check next email where CompanyIds match
;WITH EmailTable(CompanyID, Email, First_Name, Last_Name) AS (
SELECT E.CompanyID, E.Email, P.First_Name, P.Last_Name
From Table_Emails as E
Left Table_People as P
ON E.EmployeeID = P.EmployeeID
Where E.CompanyID = @CoId
And E.Email LIKE P.First_Name + '[_]' + P.Last_Name + '@%')
Select TOP(2) @condition = 0
FROM EmailTable
Having COUNT(*) > 1
-- If email matches previous email, log Company Id with the email type
IF @condition = 0
PRINT CONVERT(VARCHAR(50), @CoId) + ' has email like firstName_lastName@CompanyAddress.domain'
-- If not, go to next Email check
END
IF @Email LIKE LEFT(@FName,1) + @LName + '@%'
-- If yes, check next email where CompanyIds match
-- If email matches previous email, log Company Id with the email type
-- If it has been logged move onto next record.
Fetch NEXT FROM CoCursor
INTO @CoId, @Email, @FName, @LName
-- Once the result is logged go to next row
END
CLOSE CoCursor
DEALLOCATE CoCursor
我看到的一个解决方案使用临时表来记录以前使用过的 id,但我的雇主不希望我使用临时表。 如何根据某些条件在 MSSQL 游标中跳过一行(迭代)?
谢谢!
解决方案
游标速度慢且效率低,很少需要。
这根本不需要游标。一个简单的过滤连接group by
就足够了
SELECT
CONCAT(e.CompanyID), ' has email like firstName_lastName@CompanyAddress.domain')
FROM Table_Email e
JOIN Table_People p ON p.EmployeeID = e.EmployeeID
WHERE e.Email LIKE p.First_Name + '[_]' + p.Last_Name + '@%'
GROUP BY
e.CompanyID
ORDER BY
e.CompanyID;
显然,出于某种非常奇怪的原因,您的雇主要求使用光标,我相信您会告诉他们所有不使用光标的原因。但不管怎样,你去吧:
您的原始代码仍然非常复杂,您可以使用上面的代码作为SELECT
光标来简化它。
注意游标的局部变量的使用,这意味着您不必释放它
DECLARE @CompanyID int;
DECLARE @crsr CURSOR;
SET @crsr = CURSOR FAST_FORWARD FOR
SELECT
e.CompanyID
FROM Table_Email e
JOIN Table_People p ON p.EmployeeID = e.EmployeeID
WHERE e.Email LIKE p.First_Name + '[_]' + p.Last_Name + '@%'
GROUP BY
e.CompanyID
ORDER BY
e.CompanyID;
OPEN @crsr;
FETCH NEXT FROM @crsr
INTO @CompanyID;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT CONCAT(e.CompanyID), ' has email like firstName_lastName@CompanyAddress.domain');
FETCH NEXT FROM @crsr
INTO @CompanyID;
END;
CLOSE @crsr;
推荐阅读
- python - 如何安装 djangoshop-sendcloud?
- node.js - 如何用 Mocha & Chai 模拟函数调用结果?
- abap - 在 ABAP 中将文字文本动态转换为字符串模板
- php - 运行 laravel docker shift 从 5.3 到 5.4 和 5.4 到 5.5 有问题
- php - 文件上传选项以从相机拍摄图像或从画廊中选择不适用于 Mozilla Firefox 中的 Web 应用程序
- c++ - 在 Visual Studio C++ 中链接多个库
- oracle - 为什么在相同类型/宽度的列之间复制数据时出现“ORA-12899: value too large for column”错误?
- r - R中按日期汇总总小时数
- azure-data-explorer - 在物化视图中按用户名和时间戳查找下一条记录,而无需在 Kusto 中序列化数据
- asp.net-core - 无法在 NavMenu 中加载数据