感兴趣的表格中只有 select
Only select from tables that are of interest
SQL 服务器 2016
我有很多 table
Table A Table B Table C Table D
User | DataA User | DataB User | DataC User | DataD
=========== =========== =================== =============
1 | 10 1 | 'hello' 4 | '2020-01-01' 1 | 0.34
2 | 20 2 | 'world'
3 | 30
所以一些用户有 A
,B
,C
and/or D
.
的数据
Table UserEnabled
User | A | B | C | D
=============================
1 | 1 | 1 | 0 | 0
2 | 1 | 1 | 0 | 0
3 | 1 | 0 | 0 | 0
4 | 0 | 0 | 1 | 0
Table UserEnabled
表示我们是否对对应的table中的任何数据感兴趣 A
,B
,C
and/or D
。
现在我想在 User
上加入那些 table,但我只想要 UserEnabled
table 至少有一个用户为 1 的列(即至少启用了一个用户)。理想情况下,我只想加入已启用的 tables,之后不过滤禁用的 tables 中的列。
因此对于所有用户我会得到
User | DataA | DataB | DataC
===============================
1 | 10 | 'hello' | NULL
2 | 20 | 'world' | NULL
3 | 30 | NULL | NULL
4 | NULL | NULL | '2020-01-01'
没有用户启用 D
,因此它不会出现在查询中
我打算想出一个动态的 SQL,它是在我每次根据 UserEnabled
的状态执行查询时构建的,但恐怕这在每次都需要创建庞大的数据集作为执行计划。我只想动态显示启用的数据,而不是所有 NULL 的列。
还有其他方法吗?
使用量将是一个数据sheet,每分钟最多可以生成多次。
你别无选择,只能通过动态 SQL 来解决这个问题。 select
查询在创建查询时定义了一组固定的列。没有 "variable" 列这样的东西。
你能做什么?一种方法是"play a trick"。将列存储为 JSON(或 XML)并删除空列。
另一种方法是创建一个具有您需要的特定逻辑的视图。我认为您可以根据启用的 table 中的数据更改时间,通过在触发器中更改它来维护此视图。也就是说,更改视图需要动态 SQL 因此代码不会很漂亮。
如果所有的关系都是1:1,你可以用
进行一次查询
...
FROM u
LEFT JOIN a ON u.id = a.u_id
LEFT JOIN b ON u.id = b.u_id
LEFT JOIN c ON u.id = c.u_id
LEFT JOIN d ON u.id = d.u_id
...
并在客户端使用显示逻辑来省略不相关的列。
如果 1:N 有多个关系,那么您可能不得不进行多次查询以防止出现 N1xN2 个结果。
只是因为我觉得这很有趣。
例子
Declare @Col varchar(max) = ''
Declare @Src varchar(max) = ''
Select @Col = @Col+','+Item+'.[Data'+Item+']'
,@Src = @Src+'Left Join [Table'+Item+'] '+Item+' on U.[User]=['+Item+'].[User] and U.['+Item+']=1'+char(13)
From (
Select Item
From ( Select A=max(A)
,B=max(B)
,C=max(C)
,D=max(D)
From UserEnabled
Where 1=1 --<< Use any Key Inital Filter Condition Here
) A
Unpivot ( value for item in (A,B,C,D)) B
Where Value=1
) A
Declare @SQL varchar(max) = '
Select U.[User]'+@Col+'
From @UserEnabled U
'+@Src
--Print @SQL
Exec(@SQL)
Returns
User DataA DataB DataC
1 10 Hello NULL
2 20 World NULL
3 30 NULL NULL
4 NULL NULL 2020-01-01
生成的SQL
Select A.[User],A.[DataA],B.[DataB],C.[DataC]
From UserEnabled U
Left Join TableA A on U.[User]=[A].[User] and U.[A]=1
Left Join TableB B on U.[User]=[B].[User] and U.[B]=1
Left Join TableC C on U.[User]=[C].[User] and U.[C]=1
SQL 服务器 2016
我有很多 table
Table A Table B Table C Table D
User | DataA User | DataB User | DataC User | DataD
=========== =========== =================== =============
1 | 10 1 | 'hello' 4 | '2020-01-01' 1 | 0.34
2 | 20 2 | 'world'
3 | 30
所以一些用户有 A
,B
,C
and/or D
.
Table UserEnabled
User | A | B | C | D
=============================
1 | 1 | 1 | 0 | 0
2 | 1 | 1 | 0 | 0
3 | 1 | 0 | 0 | 0
4 | 0 | 0 | 1 | 0
Table UserEnabled
表示我们是否对对应的table中的任何数据感兴趣 A
,B
,C
and/or D
。
现在我想在 User
上加入那些 table,但我只想要 UserEnabled
table 至少有一个用户为 1 的列(即至少启用了一个用户)。理想情况下,我只想加入已启用的 tables,之后不过滤禁用的 tables 中的列。
因此对于所有用户我会得到
User | DataA | DataB | DataC
===============================
1 | 10 | 'hello' | NULL
2 | 20 | 'world' | NULL
3 | 30 | NULL | NULL
4 | NULL | NULL | '2020-01-01'
没有用户启用 D
,因此它不会出现在查询中
我打算想出一个动态的 SQL,它是在我每次根据 UserEnabled
的状态执行查询时构建的,但恐怕这在每次都需要创建庞大的数据集作为执行计划。我只想动态显示启用的数据,而不是所有 NULL 的列。
还有其他方法吗?
使用量将是一个数据sheet,每分钟最多可以生成多次。
你别无选择,只能通过动态 SQL 来解决这个问题。 select
查询在创建查询时定义了一组固定的列。没有 "variable" 列这样的东西。
你能做什么?一种方法是"play a trick"。将列存储为 JSON(或 XML)并删除空列。
另一种方法是创建一个具有您需要的特定逻辑的视图。我认为您可以根据启用的 table 中的数据更改时间,通过在触发器中更改它来维护此视图。也就是说,更改视图需要动态 SQL 因此代码不会很漂亮。
如果所有的关系都是1:1,你可以用
进行一次查询...
FROM u
LEFT JOIN a ON u.id = a.u_id
LEFT JOIN b ON u.id = b.u_id
LEFT JOIN c ON u.id = c.u_id
LEFT JOIN d ON u.id = d.u_id
...
并在客户端使用显示逻辑来省略不相关的列。
如果 1:N 有多个关系,那么您可能不得不进行多次查询以防止出现 N1xN2 个结果。
只是因为我觉得这很有趣。
例子
Declare @Col varchar(max) = ''
Declare @Src varchar(max) = ''
Select @Col = @Col+','+Item+'.[Data'+Item+']'
,@Src = @Src+'Left Join [Table'+Item+'] '+Item+' on U.[User]=['+Item+'].[User] and U.['+Item+']=1'+char(13)
From (
Select Item
From ( Select A=max(A)
,B=max(B)
,C=max(C)
,D=max(D)
From UserEnabled
Where 1=1 --<< Use any Key Inital Filter Condition Here
) A
Unpivot ( value for item in (A,B,C,D)) B
Where Value=1
) A
Declare @SQL varchar(max) = '
Select U.[User]'+@Col+'
From @UserEnabled U
'+@Src
--Print @SQL
Exec(@SQL)
Returns
User DataA DataB DataC
1 10 Hello NULL
2 20 World NULL
3 30 NULL NULL
4 NULL NULL 2020-01-01
生成的SQL
Select A.[User],A.[DataA],B.[DataB],C.[DataC]
From UserEnabled U
Left Join TableA A on U.[User]=[A].[User] and U.[A]=1
Left Join TableB B on U.[User]=[B].[User] and U.[B]=1
Left Join TableC C on U.[User]=[C].[User] and U.[C]=1