Транспонирование таблицы

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
zenja
Сообщения: 17
Зарегистрирован: 17 фев 2006, 13:29

Транспонирование таблицы

Сообщение zenja » 26 июн 2006, 16:02

Есть ли способ динамически формировать запрос, который бы имел в виде столбцов значения полей одной таблицы, а строками были бы значения из другой таблицы?

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 26 июн 2006, 16:09

А зачем вам такое извращение? Приведите пример с обоснованием.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 26 июн 2006, 16:33

Кросс-запросы формируются совсем другими инструментами. Например, это отчётник какой-нибудь, типа Fast Report.
А зачем вам такое извращение? Приведите пример с обоснованием.
Колонки - клиенты, строки - товары, пересечение - сумма или количество. Да сколько угодно примеров.
Последний раз редактировалось WildSery 26 июн 2006, 16:35, всего редактировалось 1 раз.

zenja
Сообщения: 17
Зарегистрирован: 17 фев 2006, 13:29

Сообщение zenja » 26 июн 2006, 16:35

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

ФИО, кол-во акций типа 1, ... кол-во акций типа N

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

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Сообщение WildSery » 26 июн 2006, 16:36

zenja писал(а):Есть надобность (у заказчика) видеть набор данных, в котором после каждой фамилии идет количество акций разных типов...
Это однозначно отчёт. Или OLAP, что несколько выходит за рамки Firebird/Interbase.

zenja
Сообщения: 17
Зарегистрирован: 17 фев 2006, 13:29

Сообщение zenja » 26 июн 2006, 16:45

WildSery писал(а):
zenja писал(а):Есть надобность (у заказчика) видеть набор данных, в котором после каждой фамилии идет количество акций разных типов...
Это однозначно отчёт. Или OLAP, что несколько выходит за рамки Firebird/Interbase.
Да, это скорее OLAP, т.к. с отчетом все более менее ясно. :)

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 26 июн 2006, 16:51

zenja писал(а):Есть надобность (у заказчика) видеть набор данных, в котором после каждой фамилии идет количество акций разных типов, т.е. набор данных должен выглядеть так:
ФИО, кол-во акций типа 1, ... кол-во акций типа N
Есть таблицы владельцев, акций и привязки акций. Здесь N - количество типов акций у эмитента.
Так у тебя еще количество типов разное? Получается, еще саму форму отчета динамически строишь... Сходу я бы сделал так: два цикла в двух датасетах по эмитентам и типам акций. В третий передаешь в качестве параметров условия отбора по эмитенту и типу. На выходе получаешь количество акций. Полученные данные скармливаешь отчету. Коряво конечно, есть варианты и лучше, но надо думать.
А никак нельзя количество типов акций сделать стабальным? То есть их всего пять или шесть и т.д. И это число не изменяется.

zenja
Сообщения: 17
Зарегистрирован: 17 фев 2006, 13:29

Сообщение zenja » 26 июн 2006, 17:01

2 CyberMax
Ну, отчет в этом случае совсем не нужен. Набор должен показываться в гриде.
А постоянным количество типов акций можно сделать только путем указания заведомо достаточного числа, например, 20 (думаю, что у эмитента вряд ли будет столько акций разного рода).

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 26 июн 2006, 17:33

Тебе же нужен способ формировать запрос? Тогда легко:
1. Создаешь и открываешь SQLTypeAction (TIBSQL) с запросом select id from type_action с сортировкой по id (выбираем все типы акций).
2. Создаешь датасет для сетки.
3. Генерируем запрос.

Код: Выделить всё

DataSet.SelectSQL.Add('SELECT');
DataSet.SelectSQL.Add('    C.ID,');
while not SQLTypeAction.EOF do
  DataSet.SelectSQL.Add('    (SELECT COUNT(*) FROM ACT_CLIENT WHERE (ID_CLIENT = C.ID_CLIENT) AND (ID_TYPE_ACTION = ' + SQLTypeAction.FieldByName('ID').AsString + ')),';
DataSet.SelectSQL.Add('    C.NAME');
DataSet.SelectSQL.Add('FROM');
DataSet.SelectSQL.Add('    CLIENT C');
DataSet.SelectSQL.Add('ORDER BY');
DataSet.SelectSQL.Add('    NAME');
Протестируй только. Я с головы писал. Но логика именно такая.

zenja
Сообщения: 17
Зарегистрирован: 17 фев 2006, 13:29

Сообщение zenja » 26 июн 2006, 17:56

Спасибо!
Я почти тоже самое сделала. Получается, что это можно только на клиенте. Ну или динамический SQL в процедуре.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 26 июн 2006, 18:14

Ну или динамический SQL в процедуре.
не надо ужасных идей или фантазий. процедура не может возвращать произвольный набор столбцов.

zenja
Сообщения: 17
Зарегистрирован: 17 фев 2006, 13:29

Сообщение zenja » 27 июн 2006, 01:26

Конечно же не может. Но если описать выходных переменных штук эдак 10 (из расчета, что самое большое количество динамических столбцов будет 8-9), то очень даже можно.
Только не очень красиво...

CyberMax
Заслуженный разработчик
Сообщения: 638
Зарегистрирован: 31 янв 2006, 09:05

Сообщение CyberMax » 27 июн 2006, 01:41

zenja писал(а):Конечно же не может. Но если описать выходных переменных штук эдак 10 (из расчета, что самое большое количество динамических столбцов будет 8-9), то очень даже можно.
Только не очень красиво...
Никогда не применяй решения, работоспособность которых зависит от подобных факторов. Вон, сам Б. Гейтс заявлял, что "640 кб хватит всем". И где теперь эти 640 кб? Может, пройдет пару лет, и 10 мало будет. Потом 20... Тогда как код через дин. формирование select'а будет работать всегда.

Slava Ekimov
Сообщения: 44
Зарегистрирован: 26 окт 2004, 14:30

Сообщение Slava Ekimov » 27 июн 2006, 13:29

zenja писал(а):Конечно же не может.
Зато может динамическая процедура aka EXECUTE BLOCK в FB 2.

PS Что это я несу, действительно простого SELECT-a достаточно

Gera
Сообщения: 53
Зарегистрирован: 12 мар 2008, 17:34

Сообщение Gera » 26 мар 2008, 13:30

Вот как заявленная задача решалась на MSSQL2005

Таблицы:

Код: Выделить всё

Parameter(
  CODE VARCHAR(25),
  NAME VARCHAR(100))

Account_Parameter(
  ID_Account INT,
  Parameter VARCHAR(25), --ссылка на Parameter.Code
  Float_Value Float)

Код: Выделить всё

DECLARE @Par NVARCHAR(MAX), @Col NVARCHAR(MAX)
SET @Par = N''
SET @Col = N''
DECLARE @Sql NVARCHAR(MAX)
SELECT 
  @Col = @Col + N',SUM(CASE WHEN Parameter=''' + Code + N''' THEN Float_Value END) AS ['+Name+N']',
  @Par = @Par + N''''+ Code + N''','
FROM Parameter
WHERE ...
SET @Par = LEFT(@Par, LEN(@Par) - 1)

SET @Sql = N'SELECT ID_Account,'+@Col+
N'FROM Account_Parameter
WHERE Parameter IN (' + @Par+ N')
GROUP BY ID_Account'

EXEC SP_EXECUTESQL @SQL
Можно посидеть полчасика и перенести на FB
Думаю идея понятна.

Ответить