Выберите только из таблиц, которые представляют интерес - PullRequest
1 голос
/ 31 января 2020

SQL Сервер 2016

У меня есть несколько таблиц

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 и / или 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

Таблица UserEnabled указывает, заинтересованы ли мы в каких-либо данных в соответствующих таблицах A, B, C и / или D.

Теперь я хочу объединить эти таблицы на User, но мне нужны только столбцы, в которых в таблице UserEnabled есть хотя бы один пользователь с 1 (ie хотя бы с одним включенным пользователем). В идеале я хочу присоединиться только к тем таблицам, которые включены, а не отфильтровывать столбцы из отключенных таблиц впоследствии.

Поэтому в результате для всех пользователей я получу

User | DataA |  DataB  | DataC
===============================
  1  |  10   | 'hello' | NULL
  2  |  20   | 'world' | NULL
  3  |  30   |  NULL   | NULL
  4  | NULL  |  NULL   | '2020-01-01'

Ни один пользователь не имеет D включен, поэтому он не отображается в запросе

Я собирался создать динамический c SQL, который создается каждый раз, когда я выполняю запрос в зависимости от состояния UserEnabled но я боюсь, что это будет плохо работать с огромным набором данных, так как каждый раз нужно будет создавать план выполнения. Я хочу динамически отображать только включенные данные, а не столбцы со всеми значениями NULL.

Есть ли другой способ?

При использовании будет таблица данных, которая может быть сгенерирована несколько раз за минут.

Ответы [ 3 ]

2 голосов
/ 31 января 2020

У вас нет выбора, кроме как подойти к этому через динамику c SQL. Запрос select имеет фиксированный набор столбцов, определенных при создании запроса. Нет такой вещи, как «переменные» столбцы.

Что вы можете сделать? Один из способов - «подшутить». Сохраните столбцы как JSON (или XML) и удалите пустые столбцы.

Другой способ - создать представление с указанными c logi c необходимыми вам значениями. Я думаю, вы можете сохранить это представление, изменив его в триггере, в зависимости от того, когда изменяются данные в включенной таблице. Тем не менее, изменение представления требует динамического c SQL, поэтому код не будет красивым.

1 голос
/ 31 января 2020

Просто потому, что я думал, что это может быть забавно.

Пример

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)

Возвращает

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
0 голосов
/ 31 января 2020

Если все отношения 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
...

и использовать display logi c на клиенте, чтобы опустить ненужные столбцы.

Если более чем одно отношение равно 1: N, тогда вам, скорее всего, придется выполнить несколько запросов, чтобы предотвратить результаты N1xN2.

...