Sql server 基于主查询的结果运行SQL子查询
有更好的方法吗 下面的SQL Server 2008 R2表值函数运行一个查询,以确定有多少记录符合特定条件,然后根据第一个查询的结果执行另一个查询 这是正确的方法吗?还是有更好的方法达到同样的效果Sql server 基于主查询的结果运行SQL子查询,sql-server,sql-server-2008-r2,Sql Server,Sql Server 2008 R2,有更好的方法吗 下面的SQL Server 2008 R2表值函数运行一个查询,以确定有多少记录符合特定条件,然后根据第一个查询的结果执行另一个查询 这是正确的方法吗?还是有更好的方法达到同样的效果 USE [My_MSSQL_Database] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE FUNCTION [dbo].[GetActiveProfileIDForSystemID](@SystemID NVARCHAR(1
USE [My_MSSQL_Database]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[GetActiveProfileIDForSystemID](@SystemID NVARCHAR(10))
RETURNS @retActiveProfileID TABLE
(
ActiveUserProfile NVARCHAR(10)
)
AS
BEGIN
DECLARE @ProfileCount NVARCHAR(50);
DECLARE @ProfilesLookup NVARCHAR(50);
SELECT @ProfileCount = COUNT(mdl_user.id)
FROM mdl_user
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE (mdl_user_info_data.fieldid = 2)
AND (mdl_user_info_data.data LIKE @SystemID)
AND mdl_user.id NOT IN (
SELECT mdl_user.id
FROM mdl_user
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE (mdl_user_info_data.fieldid = 4)
AND (mdl_user_info_data.data LIKE 'Yes')
AND (mdl_user.deleted = 0)
)
AND (mdl_user.deleted = 0);
IF (@ProfileCount > 0)
BEGIN
SELECT @ProfilesLookup = mdl_user.id
FROM mdl_user
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE (mdl_user_info_data.fieldid = 2)
AND (mdl_user_info_data.data LIKE @SystemID)
AND mdl_user.id NOT IN (
SELECT mdl_user.id
FROM mdl_user
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE (mdl_user_info_data.fieldid = 4)
AND (mdl_user_info_data.data LIKE 'Yes')
AND (mdl_user.deleted = 0)
)
AND (mdl_user.deleted = 0)
END
ELSE
BEGIN
SELECT @ProfilesLookup = mdl_user.id
FROM mdl_user
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE (mdl_user_info_data.fieldid = 2)
AND (mdl_user_info_data.data LIKE @SystemID)
AND (mdl_user.deleted = 0)
END
IF @ProfilesLookup IS NOT NULL
BEGIN
INSERT @retActiveProfileID
SELECT @ProfilesLookup;
END
RETURN
END
mdl_user_info_data.userid是mdl_user.id上的一个隐含FK
mdl\u user.id=mdl\u user\u info\u data.userid
基本上,我想做的是:
运行一个查询,计算mdl_user_info_数据表中有多少行/记录
WHERE (mdl_user_info_data.fieldid = 4)
AND (mdl_user_info_data.data LIKE 'Yes')
及
其中,mdl\u user\u info\u data.fieldid=2
和mdl_user_info_data.data,如@SystemID
如果没有行计数=0,则我希望:
SELECT id
FROM mdl_user_info_data
WHERE mdl_user_info_data.userid = @SystemID
其中@SystemID是传递给GetActiveProfileIDForSystemID@SystemID函数在被调用时调用
mdl\u user\u info\u data.fieldid=2和
mdl\u用户\u信息\u数据.fieldid=4
行是应用程序Moodle中的用户配置文件字段
mdl_用户_信息_数据表定义为:
CREATE TABLE [dbo].[mdl_user_info_data](
[id] [bigint] IDENTITY(1,1) NOT NULL,
[userid] [bigint] NOT NULL,
[fieldid] [bigint] NOT NULL,
[data] [ntext] NOT NULL,
[dataformat] [smallint] NOT NULL,
CONSTRAINT [mdl_userinfodata_id_pk] PRIMARY KEY CLUSTERED
)
这取决于你所说的更好是什么意思 从易于理解和维护的角度来看,当前的变型可能还可以 从性能的角度来看,它很可能会得到改进,因为您执行了两次相同的查询 这里有一种可能的方法。这是我对这个函数背后逻辑的理解 有两组可能相交的ID
A:
SELECT ID
FROM T
WHERE <ExpressionA>
SELECT mdl_user.id
FROM mdl_user
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE (mdl_user_info_data.fieldid = 2)
AND (mdl_user_info_data.data LIKE @SystemID)
AND (mdl_user.deleted = 0)
B:
SELECT ID
FROM T
WHERE <ExpressionB>
SELECT mdl_user.id
FROM mdl_user
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE (mdl_user_info_data.fieldid = 4)
AND (mdl_user_info_data.data LIKE 'Yes')
AND (mdl_user.deleted = 0)
如果A-B不为空,则返回A-B;如果A-B为空,则返回A或AxB
为空,则A=AxB
我们只想返回一行,而不是整个集合。因此,我们可以返回A-B加AxB的有序并集,并获取结果的第一行
WITH
CTE_A
AS
(
SELECT ID
FROM T
WHERE <ExpressionA>
)
,CTE_B
AS
(
SELECT ID
FROM T
WHERE <ExpressionB>
)
,CTE_OrderedA
AS
(
-- A - B
SELECT 1 AS SortOrder, ID
FROM CTE_A
WHERE ID NOT IN
(
SELECT ID
FROM CTE_B
)
UNION ALL
-- A x B
SELECT 2 AS SortOrder, ID
FROM CTE_A
WHERE ID IN
(
SELECT ID
FROM CTE_B
)
)
SELECT TOP(1) ID
FROM CTE_OrderedA
ORDER BY SortOrder
;
此查询消除了显式IF的需要。现在,您可以简化函数本身并使其成为一个函数。
它应该比当前的变体更有效,但您应该使用实际数据来衡量实际性能
实际上,从维护的角度来看,可以说单个查询变量更好,因为查询的代码不会重复。
但这背后的逻辑可能并不明显。
无论如何,应该有适当的注释来解释逻辑。堆栈溢出问题有一定的复杂性,之后我们应该得到报酬来回答。@MikeNakis,事实上,函数的逻辑似乎没有那么复杂。我看不懂你的答案,我的大脑受伤了,所以我对你的努力投了赞成票!C-:=@MikeNakis,您可以看到原始代码有重复语句。本质上,原始函数只处理生成两组ID的两个查询,我在答案中称之为集合A和集合B。我只是简单地展示了如何在不使用IF的情况下实现相同的逻辑,而是使用UNION。谢谢Vladimir。我要试试那个CTE解决方案。我已经编辑了我的原创文章并添加了更多信息。一旦我尝试了你的CTE解决方案,我就会接受答案。@luisdev,你最终做了什么?我的建议有用吗?弗拉基米尔。我还在努力。一旦解决方案起作用,我会在这里发布。
WITH
CTE_A
AS
(
SELECT ID
FROM T
WHERE <ExpressionA>
)
,CTE_B
AS
(
SELECT ID
FROM T
WHERE <ExpressionB>
)
,CTE_OrderedA
AS
(
-- A - B
SELECT 1 AS SortOrder, ID
FROM CTE_A
WHERE ID NOT IN
(
SELECT ID
FROM CTE_B
)
UNION ALL
-- A x B
SELECT 2 AS SortOrder, ID
FROM CTE_A
WHERE ID IN
(
SELECT ID
FROM CTE_B
)
)
SELECT TOP(1) ID
FROM CTE_OrderedA
ORDER BY SortOrder
;