2016-06-14 7 views
0

Я использую хранимую процедуру для добавления столбцов в сетку в форме Windows.
У меня возникла проблема с динамическим добавлением новых столбцов в эту сетку.
Я использую SQL Server 2014 Management Studio.TSQL - Изменение имени случая при циклировании в хранимой процедуре

То, что я пытаюсь сделать, это использовать переменную, объявленную в SQL, для обозначения каждого столбца ... Вот пример.

@Date as date 
AS 
BEGIN 
SET NOCOUNT ON; 
DECLARE @cnt as int = 0; 
DECLARE @name as varchar(3); 
WHILE @cnt < 12 
BEGIN 
SELECT SUM(Price) as Price, Type, 
SUM(CASE WHEN dbo.myTable.Date = @Date THEN dbo.myTable.Price ELSE NULL END) AS @name 
FROM myTable 
WHERE (Date BETWEEN @Date AND DATEADD(dd, 60, @Date)) 
GROUP BY Type 
    SET @cnt = @cnt + 1 
    SET @name = @name + CONVERT(varchar(1),@cnt) 
END; 

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

Вот что мой желаемый выход ... Click Here

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

SELECT SUM(Price) as Price, Type, 
SUM(CASE WHEN dbo.myTable.Date = DATEADD(dd,1,@Date) THEN dbo.myTable.Price ELSE NULL END) AS D1, 
SUM(CASE WHEN dbo.myTable.Date = DATEADD(dd,2,@Date) THEN dbo.myTable.Price ELSE NULL END) AS D2, 
SUM(CASE WHEN dbo.myTable.Date = DATEADD(dd,3,@Date) THEN dbo.myTable.Price ELSE NULL END) AS D3, 
... 
SUM(CASE WHEN dbo.myTable.Date = DATEADD(dd,60,@Date) THEN dbo.myTable.Price ELSE NULL END) AS D60 
FROM myTable 
WHERE (Date BETWEEN @Date AND DATEADD(dd, 60, @Date)) 
GROUP BY Type 
END; 

Мне интересно, если есть это более чистый способ сделать это, используя цикл, как я пытался сделать в вышеуказанном коде.

Есть ли способ реализовать то, что я пытаюсь сделать, или я должен искать другое решение?

спасибо.

+3

Что вы хотите сделать, потребуется динамический sql, потому что имена столбцов в противном случае должны быть жестко закодированы. Но вы, приведенный выше, также неверны, чтобы выбрать что-то. Вам также не нужен цикл. Я предлагаю добавить некоторые примеры данных и желаемый набор данных (или 2), на которые люди могут ответить более конкретно. – Matt

+0

показать нам вашу структуру таблицы с данными и ожидаемым результатом, это поможет нам дать вам лучшее решение. –

+1

Как правило, вопросы не должны ссылаться на внешние изображения. Если изображение исчезает, то вопрос, вероятно, становится бесполезным для других пользователей. Вы не указываете, какое программное обеспечение базы данных вы используете. Полезно пометить вопросы базы данных как соответствующим программным обеспечением (MySQL, Oracle, DB2, ...), так и версией, например. 'SQL-сервер-2014'. Различия в синтаксисе и особенностях часто влияют на ответы.Вы ищете что-то, что может сделать «pivot»? – HABO

ответ

0

цикл while должен работать на вас.

declare 
@x varchar(2) = 1, 
@sql varchar(8000), 
@Date varchar(30) ='2016-01-01', 
@y varchar(2) = 6 

while @x < @y 
begin 

set @sql = isnull(@sql,'')+',SUM(CASE WHEN dbo.myTable.Date = DATEADD(dd,' [email protected] +' ,'+''''[email protected]+''''+') THEN dbo.myTable.Price ELSE NULL END) AS D'[email protected] + ' ' 

set @x = @x +1 

end 

set @sql = 'SELECT SUM(Price) as Price '[email protected] +' FROM myTable WHERE (Date BETWEEN '+''''[email protected]+''''+' AND DATEADD(dd,'+ @y+',' +''''[email protected]+''''+')) ' 

exec(@sql) 

, который строит этот запрос

SELECT SUM(Price) AS Price 
    ,SUM(CASE 
      WHEN dbo.myTable.DATE = DATEADD(dd, 1, '2016-01-01') 
       THEN dbo.myTable.Price 
      ELSE NULL 
      END) AS D1 
    ,SUM(CASE 
      WHEN dbo.myTable.DATE = DATEADD(dd, 2, '2016-01-01') 
       THEN dbo.myTable.Price 
      ELSE NULL 
      END) AS D2 
    ,SUM(CASE 
      WHEN dbo.myTable.DATE = DATEADD(dd, 3, '2016-01-01') 
       THEN dbo.myTable.Price 
      ELSE NULL 
      END) AS D3 
    ,SUM(CASE 
      WHEN dbo.myTable.DATE = DATEADD(dd, 4, '2016-01-01') 
       THEN dbo.myTable.Price 
      ELSE NULL 
      END) AS D4 
    ,SUM(CASE 
      WHEN dbo.myTable.DATE = DATEADD(dd, 5, '2016-01-01') 
       THEN dbo.myTable.Price 
      ELSE NULL 
      END) AS D5 
FROM myTable 
WHERE (DATE BETWEEN '2016-01-01' AND DATEADD(dd, 6, '2016-01-01')) 
+0

Спасибо, Костя! Это именно то, что я искал, так много смысла, что я не могу поверить, что сам не думал об этом! Ура! – NickC

0
-----This section is just to get me some test data to show you how it works 
DECLARE @MyTable AS TABLE ([Date] DATE, AmountType VARCHAR(10), Price INT) 
DECLARE @Date DATE = (GETDATE() - 1) 
DECLARE @Price INT = 1 

WHILE @Price < 61 
BEGIN 
    DECLARE @AmountType VARCHAR(10) 
    SET @AmountType = CASE 
     WHEN @Price%4 = 0 THEN 'Type 1' 
     WHEN @Price%4 = 1 THEN 'Type 2' 
     WHEN @Price%4 = 2 THEN 'Type 3' 
     ELSE 'Type 4' 
    END 

    INSERT INTO @MyTable ([Date], AmountType, Price) VALUES (DATEADD(d,@Price,@Date), @AmountType, @Price * 4) 
    INSERT INTO @MyTable ([Date], AmountType, Price) VALUES (DATEADD(d,@Price,@Date), @AmountType, @Price * 2) 

    SET @Price += 1 
END 

SET @Date = GETDATE() 

------------------Build A DateTable On The Fly----------------- 
DECLARE @Dates AS TABLE ([Date] DATE, DayNum VARCHAR(4)) 
DECLARE @I INT = 0 
WHILE @I < 60 
BEGIN 
    INSERT INTO @Dates ([Date], DayNum) VALUES (DATEADD(d,@I,@Date),'D' + CAST(@I + 1 AS VARCHAR(4))) 
    SET @I += 1 
END 

--You can use c# to pivot this data probably a lot easier if you do just grab your query like this 
SELECT 
    d.DayNum 
    ,t.AmountType 
    ,Price = SUM(ISNULL(t.Price,0)) 
FROM 
    @Dates d 
    LEFT JOIN @MyTable t 
    ON d.[Date] = t.[Date] 
GROUP BY 
    d.DayNum 
    ,t.AmountType 
ORDER BY 
    d.DayNum 

---- If you don't want to do the pivot in your application then you can do this: 


SELECT 
    AmountType 
    ,D1 = ISNULL(D1,0), D2 = ISNULL(D2,0), D3 = ISNULL(D3,0), D4 = ISNULL(D4,0), D5 = ISNULL(D5,0), D6 = ISNULL(D6,0), D7 = ISNULL(D7,0), D8 = ISNULL(D8,0), D9 = ISNULL(D9,0), D10 = ISNULL(D10,0), D11 = ISNULL(D11,0), D12 = ISNULL(D12,0), D13 = ISNULL(D13,0), D14 = ISNULL(D14,0), D15 = ISNULL(D15,0), D16 = ISNULL(D16,0), D17 = ISNULL(D17,0), D18 = ISNULL(D18,0), D19 = ISNULL(D19,0), D20 = ISNULL(D20,0), D21 = ISNULL(D21,0), D22 = ISNULL(D22,0), D23 = ISNULL(D23,0), D24 = ISNULL(D24,0), D25 = ISNULL(D25,0), D26 = ISNULL(D26,0), D27 = ISNULL(D27,0), D28 = ISNULL(D28,0), D29 = ISNULL(D29,0), D30 = ISNULL(D30,0), D31 = ISNULL(D31,0), D32 = ISNULL(D32,0), D33 = ISNULL(D33,0), D34 = ISNULL(D34,0), D35 = ISNULL(D35,0), D36 = ISNULL(D36,0), D37 = ISNULL(D37,0), D38 = ISNULL(D38,0), D39 = ISNULL(D39,0), D40 = ISNULL(D40,0), D41 = ISNULL(D41,0), D42 = ISNULL(D42,0), D43 = ISNULL(D43,0), D44 = ISNULL(D44,0), D45 = ISNULL(D45,0), D46 = ISNULL(D46,0), D47 = ISNULL(D47,0), D48 = ISNULL(D48,0), D49 = ISNULL(D49,0), D50 = ISNULL(D50,0), D51 = ISNULL(D51,0), D52 = ISNULL(D52,0), D53 = ISNULL(D53,0), D54 = ISNULL(D54,0), D55 = ISNULL(D55,0), D56 = ISNULL(D56,0), D57 = ISNULL(D57,0), D58 = ISNULL(D58,0), D59 = ISNULL(D59,0), D60 = ISNULL(D60,0) 
FROM 
    (
     SELECT 
      DayNum 
      ,AmountType 
      ,Price 
     FROM 
      @Dates d 
      LEFT JOIN @MyTable t 
      ON d.[Date] = t.[Date] 
    ) s 
PIVOT 
    (
     SUM(Price) 
     FOR DayNum IN ([D1],[D2],[D3],[D4],[D5],[D6],[D7],[D8],[D9],[D10],[D11],[D12],[D13],[D14],[D15],[D16],[D17],[D18],[D19],[D20],[D21],[D22],[D23],[D24],[D25],[D26],[D27],[D28],[D29],[D30],[D31],[D32],[D33],[D34],[D35],[D36],[D37],[D38],[D39],[D40],[D41],[D42],[D43],[D44],[D45],[D46],[D47],[D48],[D49],[D50],[D51],[D52],[D53],[D54],[D55],[D56],[D57],[D58],[D59],[D60]) 
    ) as p 

Чтобы ответить на некоторые замечания, между нами. Мы искали именно то, что ваш последний комментарий был таблицей или частью там, которая показала структуру таблицы, включая Date, AmountType, Price и т. Д. Таким образом, мы могли бы понять, как вы попадаете в D1, D2 и т. Д. Запустите запрос к @MyTable, чтобы увидеть пример данных, предоставляющий несколько строк, которые могли бы решить мои и другие любопытства.

Мое личное мнение заключается в том, что вы, вероятно, следует искать в прочном динамического SQL или .net решения для поворота набора данных, а не жесткого кодирования для обработки таких проблем, как отсутствие даты, изменение количества дней и т.д.

решение, представленное здесь, не использует динамический sql, который жестко закодирован в течение 60 дней и показывает вам 2 разных набора данных для вас на выбор. Я также сделал предположение, что вы ищете даты подряд, чтобы этот запрос учитывал, что цена может отсутствовать в течение этого времени и будет рассматривать его как таковой.

+0

Большое спасибо за ваш ответ. Это очень полезная информация и определенно будет хорошей ссылкой для меня. Однако я смог использовать динамический SQL для получения моего спроектированного вывода. Я вижу, что вы предложили мне провести некоторое исследование языка TSQL для решения более сложных тем. Будет ли этот вопрос рассматриваться как сложная тема? Также, если у вас есть какие-либо ссылки, которые вам нравятся, я бы очень признателен. Я благодарю вас за ваши усилия. – NickC

+0

Дело не в том, что вопрос или требование сложны, так как большую часть времени он потребует некоторых методов, которые менее используются или желательны. Динамический SQL, например, принимает определенные разрешения на доступ к базам данных и, как правило, не так желательно, если не нужен также из-за планов выполнения. PIVOT и UNPIVOT обычно являются функциями прикладного уровня. Все XML приводит к интересным ответам. В одном из исправлений, которые вы написали, вы были SQL nob. Таким образом, борьба с ними вроде как бег до ползания - это все, что я надеюсь, что вы не восприняли это отрицательно, и я отредактирую его. – Matt

+0

Я не воспринимал это отрицательно. Мне было просто любопытно, что такое «простая» и «сложная» тема, потому что я не уверен, как правильно судить о моем умении в SQL, поэтому мне было любопытно, была ли эта «простая тема», опытный "пользователь SQL знал бы, как его реализовать. – NickC

Смежные вопросы