|
|
|
Supreme Being
      
участник
Last Login: 20.02.2009 9:10
Сообщ.: 275,
Visits: 867
|
|
Здравствуйте!
Помогите, пож., правильно составить процедурку.
У меня есть таблица, в которой имеется поле Name (Имя), DateT(Дата) и поле Cnt (Количество).
В таблицу постоянно заносятся данные.
Также имеется еще одна таблица, у которой поля: DateT(Дата) и все Name какие есть в первой таблице.
Мне нужно сделать процедуру, которая считает для каждого Name из первой таблицы общее количество за день, а результат должен заносится во вторую таблицу.
Что-то такое:
tbl1
Name | DateT | Cnt
--------------------
Вася | 01.09.2006 | 3
Петя | 01.09.2006 | 2
Вася | 02.09.2006 | 3
Петя | 02.09.2006 | 7
Вася | 02.09.2006 | 5
tbl2
DateT | Вася | Петя
--------------------
01.09.2006 | 3 | 2
02.09.2006 | 8 | 7
|
|
|
|
|
Supreme Being
      
модератор
Last Login: 29.10.2007 14:45
Сообщ.: 1 833,
Visits: 16 863
|
|
| Если все именно так, как ввы напсиали (т.е. во второй таблице есть поля Вася и Петя, а не Name), то запрос будет таким: SELECT DateT, sum(case when 'Вася' then cnt else 0 end) Вася, sum(case when 'Петя' then cnt else 0 end) Петя, FROM Tbl GROUP BY DateT В другом варианте, когда структура второй таблицу вот такая (DateT, Name, Quan), то будет такой запрос: SELECT DateT, Name, Sum(cnt) Cnt FROM Tbl GROUP BY DateT, Name Есть еще один способ - использовать оператор PIVOT, однако он действителен только для 2005 сервера.
|
|
|
|
|
Supreme Being
      
участник
Last Login: 20.02.2009 9:10
Сообщ.: 275,
Visits: 867
|
|
У меня первый вариант.
Т.е. когда имена будут добавляться, то и процедуру придется менять? Я думал можно как-нибудь в цикле это сделать.
|
|
|
|
|
Supreme Being
      
модератор
Last Login: 29.10.2007 14:45
Сообщ.: 1 833,
Visits: 16 863
|
|
| Можно и в цикле и при помощи PIVOT. Однако, какая необходимость создавать для каждого имени свой столбец? Это глупость, на мой взгляд.
|
|
|
|
|
Supreme Being
модератор
Last Login: 04.05.2008 13:32
Сообщ.: 7 234,
Visits: 65 445
|
|
| Я бы шире вопрос поставил. Зачем вообще отдельная таблица? Ведь по сути она дублирует первую из которой с помощью sum/where/group by можно всегда получить нужную информацию.
|
|
|
|
|
Supreme Being
      
участник
Last Login: 20.02.2009 9:10
Сообщ.: 275,
Visits: 867
|
|
Я с вами полностью согласен, но мне поставили такую задачу :\
А как в SQL можно в цикле перебрать поля?
|
|
|
|
|
Supreme Being
      
модератор
Last Login: 29.10.2007 14:45
Сообщ.: 1 833,
Visits: 16 863
|
|
| Хмм... а для каких целей, не объяснили? Это заранее неправильный подход для ХРАНЕНИЯ данных. Подобный вид обычно применяется только в отчетах. Именно в бюазе хранить в таком виде нет никого смысла.
|
|
|
|
|
Supreme Being
      
модератор
Last Login: 29.10.2007 14:45
Сообщ.: 1 833,
Visits: 16 863
|
|
| Перебрать поля можно, к примеру, так (если дальше будете динамический SQL использовать): DECLARE @Fields varchar(1024) SET @Fields ='' SELECT @Fields=@Fields + Name + ', ' FROM syscolumns WHERE ID=(SELECT ID FROM sysobjects WHERE NAME='dom_our') SET @Fields=Substring(@Fields,1, Len(@Fields)-1) SELECT @Fields
|
|
|
|
|
Supreme Being
      
участник
Last Login: 20.02.2009 9:10
Сообщ.: 275,
Visits: 867
|
|
| Это и будет своего рода отчет за день .
|
|
|
|
|
Supreme Being
      
модератор
Last Login: 29.10.2007 14:45
Сообщ.: 1 833,
Visits: 16 863
|
|
| Тогда почитайте книжки по базам. Поверьте, полезно.
|
|
|
|
|
Supreme Being
модератор
Last Login: 04.05.2008 13:32
Сообщ.: 7 234,
Visits: 65 445
|
|
Вот такой вариант с динамическим sql можно использовать.SELECT SUM(cnt) nameCnt, name, DateT INTO #t3 FROM tbl1 WHERE DateT = '02.09.2006' GROUP BY Name, DateTWHILE EXISTS (SELECT * FROM #t3) BEGIN DECLARE @nameCnt int, @name varchar(100), @datet datetime SELECT TOP 1 @nameCnt = nameCnt, @name = name, @datet = dateT FROM #t3 DECLARE @SQLString nvarchar(500) SET @SQLString = 'UPDATE #tbl2 SET ['+@name+']=@cnt WHERE DateT=@DateT;'+ ' IF 0=@@ROWCOUNT INSERT INTO #tbl2 (DateT,['+@name+']) VALUES(@DateT, @cnt)' EXEC sp_executesql @SQLString, N'@DateT datetime, @cnt int', @DateT, @nameCnt DELETE FROM #t3 WHERE name=@name AND dateT=@datet END DROP TABLE #t3
|
|
|
|
|
Supreme Being
модератор
Last Login: 04.05.2008 13:32
Сообщ.: 7 234,
Visits: 65 445
|
|
| Мда. Забыл пояснить. Данный код использует динамический sql чтобы не было нужно менять код когда в таблице tbl1 появятся новое имя, а в tbl2 соответствующее ей поле. В первом SELECT надо сделать условоие чтобы выборка шли по текущей дате.
|
|
|
|
|
Supreme Being
      
модератор
Last Login: 29.10.2007 14:45
Сообщ.: 1 833,
Visits: 16 863
|
|
| В свою очередь, мой экзампл для MS SQL2005: CREATE TABLE History (Name varchar(100), DT datetime, Quan int) INSERT INTO History VALUES ('Вася', '01.01.2005', 5) INSERT INTO History VALUES ('Вася', '01.01.2005', 51) INSERT INTO History VALUES ('Вася', '01.01.2005', 45) INSERT INTO History VALUES ('Петя', '01.01.2005', 57) INSERT INTO History VALUES ('Петя', '01.01.2005', 4) INSERT INTO History VALUES ('Вася', '02.01.2005', 5) INSERT INTO History VALUES ('Вася', '02.01.2005', 5) INSERT INTO History VALUES ('Петя', '02.01.2005', 9) SELECT * FROM History h PIVOT (Sum(Quan) FOR Name IN ([Вася], [Петя])) as pvt DROP TABLE History Для 2000 сервера можно сделать нечто подобное, если использовать специальные хранимые процедуры, к примеру, эту: http://www.sql.ru/faq/faq_topic.aspx?fid=358
|
|
|
|
|
Supreme Being
      
участник
Last Login: 20.02.2009 9:10
Сообщ.: 275,
Visits: 867
|
|
| Спасибо большое! Исчерпывающе :)
|
|
|
|
|
Supreme Being
      
участник
Last Login: 20.02.2009 9:10
Сообщ.: 275,
Visits: 867
|
|
Еще вопрос:
Если мне нужно обновить какое-то поле в таблице, то я пишу так:
UPDATE tbl1 SET Ivan=57 FROM tbl1 WHERE DateT='09.02.2006'
А если я заранее не знаю как называется поле и только после всяких манипуляций узнаю, что поле называется Ivan и записано у меня это примерно так @name='Ivan', то как мне записать запрос на обновление?
Имя поля я узнал при таком запросе:
SELECT column_name, as Automat FROM [ХХХ].information_schema.columns WHERE table_name = 'tbl1'
|
|
|
|
|
Supreme Being
      
модератор
Last Login: 29.10.2007 14:45
Сообщ.: 1 833,
Visits: 16 863
|
|
| Да вы, батенька, извращенец)) а) Ваш запрос лучше будет выглядеть так: UPDATE tbl1 SET Ivan=57 WHERE DateT='09.02.2006' б) Используйте динамический SQL. Как - читайте BOL. Потрудитесь хоть что-то сами найти.
|
|
|
|
|
Supreme Being
      
участник
Last Login: 20.02.2009 9:10
Сообщ.: 275,
Visits: 867
|
|
:) Что есть - то есть
Если б я еще понимал что искать в BOL
|
|
|
|
|
Supreme Being
модератор
Last Login: 04.05.2008 13:32
Сообщ.: 7 234,
Visits: 65 445
|
|
| По моему только через динамический SQL такое решается. Формируем строку и выполняем ее через sp_executesql.
|
|
|
|
|
Supreme Being
      
участник
Last Login: 20.02.2009 9:10
Сообщ.: 275,
Visits: 867
|
|
А! Понятно! Т.е. вот так:
set @sqlstr='Update tbl1 set '+@name+'='+@cnt+' Where dateT=09.19.2006'
exec(@sqlstr)
|
|
|
|
|
Supreme Being
      
модератор
Last Login: 29.10.2007 14:45
Сообщ.: 1 833,
Visits: 16 863
|
|
| ага... только перед этим сделайте PRINT строки и посомтрите что у вас получилось.
|
|
|
|