использовать выбранные значения sql в качестве имен строк для другого выбора - PullRequest
3 голосов
/ 24 января 2011

На MSSQL-сервере, учитывая таблицы:

TABLE values {
    int id;
    timestamp date;
    int value;
}

TABLE value_type {
    int value_id; // foreign key on values.id
    text name;
}

Я могу выполнить запрос вроде:

SELECT date, name, value
FROM values
LEFT JOIN value_type ON value_id = id;

и получить что-то вроде:

+----------+------+-------+
| date     | name | value |
+----------+------+-------+
| 01.01.10 | foo  |  1.0  |
+----------+------+-------+
| 01.01.10 | bar  |  2.0  |
+----------+------+-------+
| 02.01.10 | bar  |  4.0  |
+----------+------+-------+
| 03.01.10 | foo  |  5.0  |
+----------+------+-------+

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

+----------+------+-------+
| date     | foo  | bar   |
+----------+------+-------+
| 01.01.10 | 1.0  |  2.0  |
+----------+------+-------+
| 02.01.10 | NULL |  4.0  |
+----------+------+-------+
| 03.01.10 | 5.0  |  NULL |
+----------+------+-------+

Структура базы данных намного сложнее, и, к сожалению, я не могу ее изменить.

РЕДАКТИРОВАТЬ : в решении не следует использовать foo и bar в качестве жестко закодированных значений в запросе.

Ответы [ 4 ]

2 голосов
/ 24 января 2011

Для SQL Server 2005+ вы можете использовать динамический SQL и PIVOT.

DECLARE @ValuesNames NVARCHAR(4000), @Query NVARCHAR(MAX)
SET @ValuesNames = ''

SELECT @ValuesNames = @ValuesNames + QUOTENAME([name]) + ','
FROM [values] A
INNER JOIN value_type B
ON B.value_id = A.id
GROUP BY [name]
ORDER BY [name]

SET @ValuesNames = LEFT(@ValuesNames,LEN(@ValuesNames)-1)

SET @Query = '
SELECT [date], '+@ValuesNames+'
FROM (  SELECT [date], [name], value
        FROM [values]
        LEFT JOIN value_type ON value_id = id) A
PIVOT(SUM(value) FOR [name] IN ('+@ValuesNames+')) AS PT
'
EXEC sp_executesql @Query
2 голосов
/ 24 января 2011

Вы можете group by Дата:

SELECT  Date
,       max(case when vt.name = 'foo' then v.value end) as Foo
,       max(case when vt.name = 'bar' then v.value end) as Bar
FROM Values v
LEFT JOIN 
        value_type vt
ON      vt.value_id = v.id
group by
        Date

Кстати, внешний ключ кажется необычным.Я бы ожидал столбец value_type в таблице values, а не столбец value_id в таблице values_type!Значений гораздо больше, чем типов значений, верно?

РЕДАКТИРОВАТЬ: В SQL нет способа генерировать переменное число столбцов, поэтому вам придется прибегнуть к мета-SQL или динамическому SQL.Вот пример:

create table [values] (id int, date datetime, value float)
insert [values] values (1, '2010-01-01', 1.0)
insert [values] values (2, '2010-01-01', 2.0)
insert [values] values (3, '2010-01-02', 4.0)
insert [values] values (4, '2010-01-03', 5.0)
create table value_types (value_id int, name varchar(max))
insert value_types values (1,'foo'), (2,'bar'), (3,'bar'), (4,'foo')

declare @sql varchar(max)
set @sql = ''
select  @sql = @sql + ',       max(case when vt.name = ''' + 
                   name + ''' then v.value end) as ' + name + CHAR(13) + CHAR(10)
from    value_types
group by
        name

set @sql = 'SELECT  Date
' + @sql + 
'FROM   [values] v
LEFT JOIN 
        value_types vt
ON      vt.value_id = v.id
group by
        Date'

exec (@sql)

Это печатает:

Date        bar     foo
----------- ------- -------
2010-01-01  2       1
2010-01-02  4       NULL
2010-01-03  NULL    5
0 голосов
/ 24 января 2011

непроверено: вы можете определить представление для объединения таблиц в паре pk-fk, а затем попробовать что-то вроде этого:

Select date, 

case name when "foo" then value else null end as foo, 

case name when "base" then value else null end as bar 

from mytable  

order by date

Здесь вам нужно заранее знать диапазон возможных значений.

Чтобы сделать его более гибким, вы можете построить динамический оператор case из различных значений «name» в хранимой процедуре и вызвать exec () для этой строки.

0 голосов
/ 24 января 2011

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

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