Сумма конкретных значений в SQL

Я пытаюсь найти сумму определенных значений в таблице, используя SQL. Примерная таблица:

+-------+-------+-------+-------+-------+-------+-------+
|  ID   |  Co1  |  Va1  |  Co2  |  Va2  |  Co3  |  Va3  |
+-------+-------+-------+-------+-------+-------+-------+
|  01   |  AA1  |   23.0|  AA2  |   11.2|  AA3  | 328.34|
|  02   |  AA2  |   27.0|  AA3  | 234.56|  AA4  |   23.8|
|  03   |  AA1  | 409.01|  AA4  | 234.98| NULL  | NULL  |
+-------+-------+-------+-------+-------+-------+-------+

У меня есть 35 таких столбцов и значений «Код».

Мне нужно выбрать таблицу, имеющую только один код. Скажем, мне нужен код AA3, это будет (столбец «Код» здесь не требуется, а только для того, чтобы показать, откуда я взял значения):

+-------+-------+--------+
|  ID   | Code  |  Value |
+-------+-------+--------+
|  01   |  AA3  |  328.34|
|  02   |  AA3  |  234.56|
|  03   |  AA3  |       0|
+-------+-------+--------+

А позже мне понадобится другой (отдельный) запрос, содержащий сумму нескольких кодов, например сумму кодов AA1 и AA2 вместе.

+-------+---------+
|  ID   |   Value |
+-------+---------+
|  01   |     34.2|
|  02   |     27.0|
|  03   |   409.01|
+-------+---------+

Я думал о том, чтобы иметь «ГДЕ» и запускать каждые 35 столбцов, но это было бы действительно утомительно и не кажется слишком эффективным. Мне было интересно, есть ли способ сделать это через SQL (я могу сделать это с помощью Excel с оператором if, и это творит чудеса).

Может быть, если бы был способ «поиска» по строке, вернуть имя столбца, а затем использовать это имя столбца для получения номера?

Дайте мне знать, если вам нужна дополнительная информация =)


person Jerry    schedule 06.08.2012    source источник
comment
Какую СУБД вы используете, SQL Server, Oracle, MySQL? В первом предложении вы говорите «Используя SQL», вы имеете в виду MS SQL Server? На последний вопрос, у вас есть только 3 столбца кода? SUM будет только для комбинаций AA1 ​​и AA2 или более?   -  person Yaroslav    schedule 06.08.2012
comment
Ах да, мой плохой. Я использую SQL Server 2008R2.   -  person Jerry    schedule 06.08.2012
comment
Я почему-то не увидел другого вашего комментария... ну да ладно. Да, на самом деле есть 35 столбцов кода и 35 столбцов сумм. Коды варьируются от AA1 до AA652. А для второй части (добавление нескольких кодов) мне нужно добавить 9 кодов: АА74, АА76, АА78 и так далее.   -  person Jerry    schedule 06.08.2012


Ответы (2)


Вам следует хранить данные в нормализованной форме.

Однако...

select SUM(v)
from
(

select * -- ID, r, v 
from 
(select * from yourtable) u
unpivot
( r for co in (co1, co2, co3)) as u1
unpivot
(  v for va in (va1, va2, va3)) as u2
where RIGHT(co,1) = RIGHT(va,1)
) v
WHERE R = 'AA1' -- etc

вернет результаты, которые вы ищете

person podiluska    schedule 06.08.2012
comment
Я хочу, чтобы это нормализовалось! ›.‹ Так было бы намного проще. Хм, не могли бы вы объяснить это немного для меня? Я новичок в SQL (^^;) Например, 'FOR' делает цикл? И я не уверен, почему вы взяли левый символ справа в «значении» в выражении WHERE... - person Jerry; 06.08.2012
comment
UNPIVOT берет денормализованную таблицу, подобную вашей, и нормализует ее (т. е. делает ее более вертикальной и менее горизонтальной). Однако он может обрабатывать только один тип данных, поэтому вам нужно сделать это дважды, чтобы получить оба типа. ПРАВО сопоставляет последний символ текстовых данных (CO1, CO2) с последним символом данных значения (VA1, VA2). Попробуйте заменить SUM(V) на *, чтобы увидеть весь набор данных - person podiluska; 06.08.2012
comment
Ах! Я думал, что вы берете значения в столбце value и берете последний символ! Выбрав все, я теперь понимаю, что на самом деле это имя столбца, которому вы соответствуете. Спасибо! Это работает! : D (за исключением того, что типы данных столбцов, которые я импортировал в SQL-сервер, не совпадали... да ладно, мне придется повторно импортировать их правильно) - person Jerry; 06.08.2012
comment
@ Unknown008: Если бы вы импортировали данные самостоятельно, не могли бы вы также нормализовать их на этом этапе? Может избавить вас от многих проблем. - person MvG; 10.08.2012
comment
Ах, я не заметил вашего комментария до сих пор, извините за поздний ответ. И нет, мне предоставили такие данные. Я надеюсь, что в будущем я не получу больше таких данных. - person Jerry; 03.12.2012

Ваша структура таблицы далеко не идеальна. Я покажу вам простой пример, похожий на ваш метод IF на основе Excel, а затем гораздо более простой запрос с нормализованной структурой данных.

SELECT
  id,
    CASE WHEN co1 = 'AA1' THEN co1 ELSE 0 END
  + CASE WHEN co2 = 'AA1' THEN co2 ELSE 0 END
  + CASE WHEN co3 = 'AA1' THEN co3 ELSE 0 END
  + CASE WHEN co4 = 'AA1' THEN co4 ELSE 0 END
  + etc, etc
FROM
  yourTable

При 30 кодах на id вам потребуется 30 операторов CASE.

Альтернативой является наличие нескольких строк данных на id вместо нескольких столбцов на id.

+-------+-------+-------+-------+
|  ID   |  Obs  |  Cod  |  Val  |
+-------+-------+-------+-------+
|  01   |   1   |  AA1  |  23.0 |
|  01   |   2   |  AA2  |  11.2 |
|  01   |   3   |  AA3  | 328.34|
|  02   |   1   |  AA2  |   27.0|
|  02   |   2   |  AA3  | 234.56|
|  02   |   3   |  AA4  |   23.8|
|  03   |   1   |  AA1  | 409.01|
|  03   |   2   |  AA4  | 234.98|
+-------+-------+-------+-------+ 

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

 Query if one id can have several           Query if one id can only have one
 observations for the same code:            observation for any one code:
----------------------------------         -----------------------------------
 SELECT                                     SELECT
   id,                                        *
   cod,                                     FROM
   SUM(val)   AS val                          yourTable 
 FROM                                       WHERE
   yourTable                                  cod = 'AA1'
 WHERE
   cod = 'AA1'
 GROUP BY
   id,
   cod
person MatBailie    schedule 06.08.2012
comment
Да, именно поэтому я не очень хотел иметь 35 операторов WHERE, ха-ха x3 Но нет, я бы не смог так отсортировать, особенно с несколькими тысячами записей =( Все равно спасибо за ваш ответ =) - person Jerry; 06.08.2012
comment
@ Unknown008. Однако имейте в виду, что SQL не предназначен для вашего типа структуры таблиц. Вам нужно либо предварительно обработать данные (см. pivot ответ на ваш вопрос) [потенциально большие накладные расходы на обработку при каждом выполнении], либо нормализовать данные до уровня, подходящего для РСУБД/SQL [значительные инвестиции для рефакторинга ваших данных] или иметь очень избыточный код [потенциально большие накладные расходы на кодирование и обслуживание]. Извините, похоже, у вас есть устаревшая проблема (структура данных), которая загоняет вас в угол, где нет «идеальных» подходов. - person MatBailie; 06.08.2012
comment
@ Unknown008 - Кроме того, обратите внимание, что существует множество способов довольно быстро нормализовать ваши данные. Несколько тысяч записей на самом деле не очень много. - person MatBailie; 06.08.2012
comment
Ясно, спасибо за комментарии Демс =) На самом деле мы просим данные быть более упорядоченными для следующего раза; наличие одного столбца для каждого кода, и это должно упростить задачу с помощью простого SELECT SUM(column) FROM table GROUP BY id. Думаю, на этот раз мы будем придерживаться Excel. - person Jerry; 06.08.2012