«Поворот» таблицы в SQL (т.е. кросс-табуляция / кросс-табуляция) - PullRequest
4 голосов
/ 17 октября 2008

Я пытаюсь сгенерировать отчет из пары таблиц базы данных. Упрощенная версия выглядит следующим образом

Campaign
----------
CampaignID

Source
-----------------------
Source_ID | Campaign_ID

Content
---------------------------------------------------------
Content_ID | Campaign_ID | Content_Row_ID | Content_Value

Отчет должен читаться так:

CampaignID - SourceID - ContentRowID(Value(A)) - ContentRowID(Value(B))

Где ContentRowID (Значение (A)) означает «Найти строку с заданным CampaignID и ContentRowId, равным« A », а затем получить ContentValue для этой строки»

По сути, я должен "повернуть" (я думаю, что это правильный термин) строки в столбцы ...

Это база данных Oracle 10g ...

Есть предложения?

Ответы [ 9 ]

2 голосов
/ 18 октября 2008

Билл Карвин упоминает об этом, но я думаю, что на это стоит очень четко указать:

SQL не выполняет то, о чем вы просите, поэтому любое «решение», которое вы получите, будет клочком.

Если вы знаете , то наверняка он всегда будет работать на Oracle 10, тогда, конечно, кросс-табуляция Уолтера Митти может это сделать. Правильный способ сделать это - создать простую комбинацию порядка сортировки в запросе и коде приложения, чтобы правильно его расположить.

  • Работает в других системах баз данных,
  • он не рискует разрушаться другими слоями (например, у MySQL есть проблема с> 255 столбцами. Вы уверены, что интерфейсная библиотека справляется так же хорошо, как и сама база данных?)
  • это (обычно) не намного сложнее.

Если вам нужно, вы можете сначала запросить Content_Row_ID s, а затем запросить все необходимые вам строки, упорядоченные по CampaignID, ContentRowID, что даст вам каждую (заполненную) ячейку в левой направо, построчно.


Ps.

Есть куча вещей, которые, по мнению современного человека, должен иметь / делать SQL, которых просто нет. Это один, сгенерированные диапазоны - это другое, рекурсивное закрытие, параметрический ORDER BY, стандартизированный язык программирования ... список можно продолжить. (хотя, по общему признанию, есть уловка для ORDER BY)

1 голос
/ 18 октября 2008

Билл Карвин и Андерс Эурениус правы в том, что не существует простого решения, а также не существует никакого решения, если число результирующих значений столбцов заранее неизвестно. Oracle 11g несколько упрощает это с помощью оператора PIVOT , но столбцы все еще должны быть известны заранее, и это не соответствует критериям 10g вашего вопроса.

1 голос
/ 18 октября 2008

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

SELECT CA.Campaign_ID, 
  C1.Content_Value AS "39100",
  C2.Content_Value AS "39200",
  C3.Content_Value AS "39300"
FROM Campaign CA
  LEFT OUTER JOIN Content C1 ON (CA.Campaign_ID = C1.Campaign_ID 
    AND C1.Content_Row_ID = 39100)
  LEFT OUTER JOIN Content C2 ON (CA.Campaign_ID = C2.Campaign_ID 
    AND C2.Content_Row_ID = 39200)
  LEFT OUTER JOIN Content C3 ON (CA.Campaign_ID = C3.Campaign_ID 
    AND C3.Content_Row_ID = 39300);

По мере того, как число различных значений увеличивается, этот запрос становится слишком дорогим для эффективного выполнения. Возможно, проще получить данные проще и переформатировать их в PL / SQL или в коде приложения.

1 голос
/ 18 октября 2008

Если у вас нет динамического числа столбцов и ваш набор данных не слишком большой, вы можете сделать это ...

SELECT CampaignID, SourceID, 
   (SELECT Content_Value FROM Content c 
      WHERE c.Campaign_ID=s.Campaign_ID 
      AND Content_Row_ID = 39100 
      AND rownum<=1) AS Value39100,
   (SELECT Content_Value FROM Content c 
      WHERE c.Campaign_ID=s.Campaign_ID 
      AND Content_Row_ID = 39200 
      AND rownum<=1) AS Value39200
FROM Source s;

Повторите подзапрос для каждого дополнительного Content_Row_ID.

1 голос
/ 17 октября 2008

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

Для начала вам нужна временная таблица:

CREATE TABLE pivot (count integer);
INSERT INTO pivot VALUES (1);
INSERT INTO pivot VALUES (2);

Теперь мы готовы к запросу.

SELECT campaignid, sourceid, a.contentvalue, b.contentvalue
FROM content a, content b, pivot, source
WHERE source.campaignid = content.campaignid
AND pivot = 1 AND a.contentrowid = 'A'
AND pivot = 2 AND b.contentrowid = 'B'
0 голосов
/ 07 июля 2010

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

Удачи

Select DS.Cla,
Sum(case
when (Extract(year from DS.Data) =:intYear) then DS.PRE
else 0
end) as ToTal,
Sum(case
when (Extract(month from DS.Data) =1) then DS.PRE
else 0
end) as Jan,
Sum(case
when (Extract(month from DS.Data) =2) then DS.PRE
else 0
end) as FEV,
Sum(case
when (Extract(month from DS.Data) =3) then DS.PRE
else 0
end) as MAR,
Sum(case
when (Extract(month from DS.Data) =4) then DS.PRE
else 0
end) as ABR,
Sum(case
when (Extract(month from DS.Data) =5) then DS.PRE
else 0
end) as MAI,
Sum(case
when (Extract(month from DS.Data) =6) then DS.PRE
else 0
end) as JUN,
Sum(case
when (Extract(month from DS.Data) =7) then DS.PRE
else 0
end) as JUL,
Sum(case
when (Extract(month from DS.Data) =8) then DS.PRE
else 0
end) as AGO,
Sum(case
when (Extract(month from DS.Data) =9) then DS.PRE
else 0
end) as SETE,
Sum(case
when (Extract(month from DS.Data) =10) then DS.PRE
else 0
end) as OUT,
Sum(case
when (Extract(month from DS.Data) =11) then DS.PRE
else 0
end) as NOV,
Sum(case
when (Extract(month from DS.Data) =12) then DS.PRE
else 0
end) as DEZ
from Dados DS
Where DS.Cla > 0
And Extract(Year from DS.Data) = :intYear
group by DS.CLA

Union All

Select 0*count(DS.cla),  0*count(DS.cla),
Sum(case
when (Extract(month from DS.Data) =1) then DS.PRE
else 0
end) as JAN,
Sum(case
when (Extract(month from DS.Data) =2) then DS.PRE
else 0
end) as FEV,
Sum(case
when (Extract(month from DS.Data) =3) then DS.PRE
else 0
end) as MAR,
Sum(case
when (Extract(month from DS.Data) =4) then DS.PRE
else 0
end) as ABR,
Sum(case
when (Extract(month from DS.Data) =5) then DS.PRE
else 0
end) as MAI,
Sum(case
when (Extract(month from DS.Data) =6) then DS.PRE
else 0
end) as JUN,
Sum(case
when (Extract(month from DS.Data) =7) then DS.PRE
else 0
end) as JUL,
Sum(case
when (Extract(month from DS.Data) =8) then DS.PRE
else 0
end) as AGO,
Sum(case
when (Extract(month from DS.Data) =9) then DS.PRE
else 0
end) as SETE,
Sum(case
when (Extract(month from DS.Data) =10) then DS.PRE
else 0
end) as OUT,
Sum(case
when (Extract(month from DS.Data) =11) then DS.PRE
else 0
end) as NOV,
Sum(case
when (Extract(month from DS.Data) =12) then DS.PRE
else 0
end) as DEZ
from Dados DS
Where DS.Cla > 0
And Extract(Year from DS.Data) = :intYear
0 голосов
/ 03 декабря 2008

Если вы не знаете количество столбцов, просто верните обычный SQL-запрос и используйте код на стороне сервера, как я перечислил здесь: Заполнение Datagrid и Sql-запроса

0 голосов
/ 18 октября 2008

Если у вас есть «Oracle, полный справочник», поищите раздел, озаглавленный «Поворот стола на бок». Здесь приводятся подробные примеры и инструкции по выполнению разворота, хотя в издании, которое у меня есть, это не называется сводкой.

Другим термином «поворот стола» является кросс-табуляция.

Одним из самых простых инструментов для кросс-таблицы является MS Access. Если у вас есть MS Access, и вы можете установить связь таблицы из базы данных Access с вашей исходной таблицей, вы уже на полпути.

В этот момент вы можете запустить «Мастер запросов» и попросить его создать кросс-таблицу для вас. Это действительно так же просто, как отвечать на вопросы, которые задает вам волшебник. Неудачная сторона этого решения заключается в том, что, если взглянуть на результирующий запрос в представлении SQL, вы увидите некоторый SQL, свойственный диалекту Access SQL и, в общем, не применимый на других платформах.

Вы также можете загрузить некоторые простые инструменты анализа с веб-сайта Oracle и использовать один из этих инструментов для выполнения кросс-таблицы за вас.

Еще раз, если вы действительно хотите сделать это на SQL, вам поможет «Oracle, полный справочник».

0 голосов
/ 18 октября 2008

Если вам нужно динамическое количество столбцов, я не верю, что это можно сделать в стандартном SQL, что, увы, превышает мои знания. Но есть функции Oracle, которые могут это сделать. Я нашел некоторые ресурсы:

http://www.sqlsnippets.com/en/topic-12200.html

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:124812348063#41097616566309

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