感兴趣的表格中只有 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