Передача нескольких идентификаторов для возврата столбцов в выражении case - PullRequest
0 голосов
/ 23 апреля 2019

Я использую динамический SQL для возврата некоторых столбцов в зависимости от типа подписки.У меня проблема с несколькими типами подписки.Хотя я могу грамотно обрабатывать 1 тип подписки.Я не могу понять, как обрабатывать 2 типа подписки.Всего у меня есть 8 различных типов.

Например:

DECLARE @subType tinyint = 2

DECLARE @Id varchar(4) = 'U01'
DECLARE @SQLProjectDetails nvarchar(MAX)

SET @SQLProjectDetails = N'SELECT ' +
       STUFF(
            -- General Information 

            CASE WHEN @subType IN (1,2,3,4) THEN N',' + NCHAR(13) + 
                 NCHAR(10) + N'        wf1.Id' ELSE N'' END + 
            CASE WHEN @subType IN (1,2) THEN N',' + NCHAR(13) + 
                 NCHAR(10) + N'        wf1.Name' ELSE N'' END + 
            CASE WHEN @subType IN (5,6,8) THEN N',' + NCHAR(13) + 
                 NCHAR(10) + N'       wf1.OtherNames' ELSE N'' END +
            CASE WHEN @subType IN (1,2) THEN N',' + NCHAR(13) + 
                 NCHAR(10) + N'        wf1.CountryName' ELSE N'' END +
             , 1, 10,N'') + NCHAR(13) + NCHAR(10) +
            N'FROM Table wf1where (wf1.Id= @p)';

EXEC sp_executesql @SQLProjectDetails,  N'@p varchar(4)', @p = @Id; 

Но что, если у меня тип подписки 2 и 5?

Значит, столбец с другими именами также будет возвращен?Основная проблема, которую я имею, - это 8 разных типов подписки.Хотя я мог бы попытаться охватить все возможные варианты, я бы предпочел сделать это динамически (главным образом потому, что существует 40000 разных вариантов).

1 Ответ

0 голосов
/ 23 апреля 2019

Если у вас была таблица ColLookup, как это:

SubType, ColumnName
1,wf1.Id
2,wf1.Id
3,wf1.Id
4,wf1.Id
1,wf1.Name
2,wf1.Name
5,wf1.OtherNames
6,wf1.OtherNames
8,wf1.OtherNames
1,wf1.CountryName
2,wf1.CountryName

Тогда такой SQL-код даст вам имена столбцов, которые вы должны извлечь:

SELECT 
  STRING_AGG(l.ColumnName, ',') as ColList
FROM
  otherTable o
  INNER JOIN
  ColLookup l on o.subtype = l.subtype
WHERE
  o.id = 1234

Если бы подтип o.id 1234 был 1, этот SQL вернул бы

'wf1.Id,1,wf1.Name,wf1.CountryName'

Если бы подтип o.id X был 3, этот SQL вернул бы

'wf1.Id'

Создание полноценного SQL может выглядеть примерно так:

SELECT 
  CONCAT('SELECT ', STRING_AGG(l.ColumnName, ','), ' FROM blah')  as sq
FROM
  otherTable o
  INNER JOIN
  ColLookup l on o.subtype = l.subtype
WHERE
  o.id = 1234

Вы можете присвоить это переменной и EXEC это

Если ваш SQLS выпущен до 2017 года и не имеет STRING_AGG, используйте аналогичный метод объединения нескольких строк в одну строку, например STUFF / FOR XML PATH. Если требуется определенный порядок, добавьте столбец порядка в таблицу поиска (STRING_AGG имеет параметр WITHIN GROUP ORDER BY, я уверен, что другие методы также имеют параметры для изменения порядка объединенной строки)

Правда, я бы сделал это на C #. Я бы запустил основной запрос, который выбирает все, а затем я бы запустить:

SELECT ColName FROM ColLookup WHERE SubType in (1,5)

Я бы поместил его в словарь / хэш-набор (это с использованием псевдокода linq, но как вам угодно):

//this is a union - anything 1 can see or 5 can see
var dict = dbcontext.Wf1Table.Where(r => r == 1 || r == 5).Distinct().ToDictionary(r => r.ColumnName, r => r.ColumnName)

//this is an intersect - anything common to 1 and 5 only
var dict = dbcontext.Wf1Table.Where(r => r == 1).Intersect(dbcontext.Wf1Table.Where(r => r == 5)).ToDictionary(r => r.ColumnName, r => r.ColumnName)

//this is if you downloaded the columns into a datatable
//SELECT DISTINCT colname FROM t WHERE subtype IN (1,5) --union
//SELECT colname FROM t WHERE subtype IN (1,5) GROUP BY colname HAVING COUNT(*) = 2 --intersection
var dict = new Dictionary(string, string);
foreach(var ro in colnamedatatable)
  dict[ro.ColName] = null;

И я бы перетащил свой основной запрос в таблицу данных и удалил ненужные столбцы:

for(int c = datatable.Columns.Length -1; c >= 0; c--) //gobackwards
  if(!dict.ContainsKey(datatable.Columns[c].ColumnName))
    datatable.Columns.RemoveAt(c);

Если вы хотите упорствовать в этом в SQL, это даст пересечение:

SELECT 
  CONCAT('SELECT ', STRING_AGG(l.ColumnName, ','), ' FROM blah')  as sq
FROM
  otherTable o
  INNER JOIN
  ColLookup l on o.subtype = l.subtype
WHERE
  o.id = @id
GROUP BY
  l.ColumnName
HAVING COUNT(*) = @count_of_subtypes_for_that_id

Что-то должно знать, сколько подтипов существует для данного идентификатора; БД знает, но вам трудно руководствоваться этим, потому что вы еще не сказали, как хранятся данные. Если это правильно (несколько записей идентификаторов / таблица посредников), тогда этот запрос работает. Если это «список, разделенный запятыми», тогда (тьфу) он нуждается в разборе на две строки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...