SQL - есть команда, чтобы сделать это? - PullRequest
2 голосов
/ 18 августа 2010

У меня есть таблица, в которой на данный момент представлен длинный список устройств и информация о том, когда они были проданы. Мне нужно взять таблицу, которая бы выглядела примерно так:

Item   |  Time Sold
--------------------
  A        05/2010
  B        04/2010
  C        03/2010
  A        04/2010
  A        05/2010

И затем создайте таблицу с элементом в качестве первого столбца с количеством дат, являющихся заголовками столбцов, как показано ниже:

Item   |   Count_03/2010   |  Count_04/2010  |  Count_05/2010
-------------------------------------------------------------
  A    |         0         |         1       |        2
  B    |         0         |         1       |        0
  C    |         1         |         0       |        0

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

EDIT

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

Ответы [ 4 ]

4 голосов
/ 18 августа 2010

В SQL Server 2005 и выше есть что-то, называемое pivot, но это не одна команда, и вам нужно знать значения в столбце Время продажи. Вы можете использовать динамический сводный подход, продемонстрированный Ициком Бен-Ганом в его Inside Microsoft SQL Server 2008: T-SQL Querying book

Пример

create table #test (Item char(1),  TimeSold varchar(20))

  insert #test values('A','05/2010')
  insert #test values('B','04/2010')
  insert #test values('C','03/2010')
  insert #test values('A','04/2010')
  insert #test values('A','05/2010')

  SELECT *
FROM
(SELECT Item,TimeSold
FROM #test) AS pivTemp
PIVOT
(   COUNT(TimeSold)
    FOR TimeSold IN ([05/2010],[04/2010],[03/2010])
) AS pivTable
3 голосов
/ 18 августа 2010

Я не проверял это, но следующее должно работать.Я использую подзапросы для получения желаемых результатов:

select item, 
(select count(*) from items i where time_sold between '02/2010' AND '03/2010' i.item=item ),
(select count(*) from items i where time_sold between '03/2010' AND '04/2010' i.item=item ),
(select count(*) from items i where time_sold between '04/2010' AND '05/2010' i.item=item )
from items;
2 голосов
/ 18 августа 2010

Собственно MS-SQL не предоставляет никаких функций для отображения данных в нужном табличном формате, не зная значений, из которых вы хотите сгенерировать имена столбцов.

Существует замечательная статья о динамическом создании запросов кросс-таблиц в MS-SQL . Это взлом, но похоже, что оно должно работать.

В противном случае более гибкий подход заключается в ...

Select Distinct
Item,
Time Sold,
Count([Item])
From
MyTable
Group By
Item,
Time Sold

Это даст вам:


    Item | Time Sold | Count
    ------------------------
    A    | 05/2010   | 2
    A    | 04/2010   | 1
    B    | 04/2010   | 1
    C    | 03/2010   | 1

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

Например, вы можете использовать эти данные в инструменте отчетности для:

  • Подсчитайте все проданные вещи
  • Показать отдельный список дат
  • Показать список дат, на которые было продано больше всего товаров

Чтобы перевести его в запрошенный вами формат отчета, лучше использовать такой инструмент отчетности, как Crystal Reports или Excel.

И Excel, и Crystal Report поддерживают сводные таблицы для отображения ваших данных в табличном формате, который вы запрашиваете (и это тоже будет выглядеть намного лучше!).

1 голос
/ 18 августа 2010

Вы можете group by получить агрегированные результаты по каждому элементу. Используя sum и case, вы можете посчитать количество предметов за определенный период. Например:

select  item
,       sum(case when time_sold between '02/2010' and '03/2010' then 1 end)
,       sum(case when time_sold between '03/2010' and '04/2010' then 1 end)
,       sum(case when time_sold between '04/2010' and '05/2010' then 1 end)
from    items
group by
        item

Если у вас есть исходные таблицы в нескольких форматах, объедините их вместе в подзапрос. Я ограничу этот пример только одним диапазоном для экономии места:

select  item
,       sum(IsInRange1)
from    (
        select  item
        ,       case when time_sold between '01/2010' and '03/2010' 
                          then 1 end as IsInRange1
        from    usa_items
        union all
        select  item
        ,       case when time_sold in ('gennaio', 'febbraio', 'marzo') 
                          then 1 end
        from    italian_items
        union all
        select  item
        ,       case when time_sold between '2010-01-01' and '2010-03-01' 
                          then 1 end
        from    iso_items
        ) SubqueryAlias
group by
        item
...