Объединение нескольких строк в одну строку

#sql #sql-server

#sql #sql-сервер

Вопрос:

У меня есть такой SQL-запрос в SSMS

 select distinct (b.TransactionNumber),
(case when b.Amount > 0 then c.total else 0 end) as 'Total Sales',
(case when b.TenderID = 1 then b.Amount else 0 end) as 'Cash',
(case when b.TenderID = 20 then b.Amount else 0 end) as 'Gift Certificates'
from [Transaction] c
inner join TenderEntry b on c.TransactionNumber = b.TransactionNumber
  

но результат (см. Изображение для справки)

Вывод SQL-запроса

Это должно быть ожидаемым результатом (см. Изображение для справки)

Ожидаемый результат

Комментарии:

1. Вывод такой из-за distinct . Все, что вы ожидали, сбивает с толку. Как вы хотите агрегировать — по какому столбцу? почему / как второй столбец должен быть агрегирован?

2. Пожалуйста, объясните правила объединения строк. Как total sales устанавливается значение 0 ?

Ответ №1:

Я бы ожидал одну строку на номер транзакции, особенно с учетом вашего использования select distinct :

 select t.TransactionNumber, te.total as total_sales,
       sum(case when t.TenderID = 1 then t.Amount else 0 end) as Cash,
       sum(case when t.TenderID = 20 then t.Amount else 0 end) as Gift_Certificates
from TenderEntry te join
     Transaction t
     on te.TransactionNumber = t.TransactionNumber
group by t.TransactionNumber, te.total;
  

Это создает одну строку для каждой транзакции.

Обратите внимание на изменения в запросе:

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

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

 select TransactionNumber,
       max(case when seqnum = 1 then total end) as total_sales,
       sum(case when tenderId = 1 then amount end) as cash,
       sum(case when tenderId = 20 then amount end) as Gift_Certificates
from (select t.TransactionNumber, te.total, t.amount, t.TenderID,
           row_number() over (partition by t.TransactionNumber, t.TenderId order by t.amount) as seqnum
      from TenderEntry te join
           Transaction t
           on te.TransactionNumber = t.TransactionNumber
      where tenderid in (1, 20)
     ) x
group by t.TransactionNumber, seqnum;
  

Комментарии:

1. Это более подробный ответ, чем мой, и исправляет некоторые ошибки, поэтому я поддержал его как таковой.

2. к сожалению, когда в тендерах есть сумма (cash и gc), сумма удваивалась в зависимости от количества элементов. например, у меня есть 2 товара, а общий объем продаж составляет 500, когда дело доходит до наличных денег, он стал 1000. Будет ли в любом случае, что я все еще могу сделать это в одной строке?

3. @EimajMorales — Меня смущает общий вопрос и проблема. Было бы хорошо, если бы вы отредактировали свой вопрос. Пожалуйста, сначала опишите, как хранятся данные при выполнении транзакции (например, сколько строк создается и что в этих строках?). Во-вторых, пожалуйста, опишите, как они складываются вместе, чтобы получить желаемый результат.

4. @EimajMorales . , , Вероятно, вам следует задать новый вопрос, предоставив образцы данных, желаемые результаты и четкое объяснение логики, которую вы хотите реализовать.

Ответ №2:

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

Вероятно, вы не хотите DISTINCT , чтобы компонент был выбран. ВЫБЕРИТЕ DISTINCT найти все уникальные строки. Итак, если у вас есть 3 строки, которые имеют некоторые различия, будут показаны все три. Если, с другой стороны, было две одинаковые строки (например, они заплатили за товар стоимостью 100 долларов двумя ваучерами на 50 долларов), он просто проигнорировал бы один из них.

Вместо этого вам, вероятно, нужно ознакомиться с ‘GROUP BY’, Который позволяет находить итоговые значения и т. Д. По нескольким строкам.

Например (хотя и не тестировался)

 select 
    (b.TransactionNumber),
    (case when b.Amount > 0 then c.total else 0 end) as 'Total Sales',
    SUM(case when b.TenderID = 1 then b.Amount else 0 end) as 'Cash',
    SUM(case when b.TenderID = 20 then b.Amount else 0 end) as 'Gift Certificates'
from [Transaction] c
inner join TenderEntry b on c.TransactionNumber = b.TransactionNumber
GROUP BY (b.TransactionNumber, (case when b.Amount > 0 then c.total else 0 end))
  

В приведенном выше примере я удалил DISTINCT, добавил «СУММУ» для двух значений транзакции (наличные / сертификаты) и ГРУППИРОВКУ по номеру транзакции и общему объему продаж (поскольку это, по-видимому, является общим для всей транзакции).

Для приведенных выше данных это приведет к получению 1 строки данных для TransactionNumber = 1, с продажами = 250 (поскольку это есть во всех строках), а также итоговые суммы для денежных и подарочных сертификатов (150 и 100 соответственно, если моя математика верна).

Однако это не ваш желаемый ответ, — вы хотите, чтобы эта транзакция проходила через две строки. Во-первых, вы уверены в этом?

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

Другие примечания

  • «Транзакция» — это специальное слово в SQL Server. Вам разрешено его использовать, но я бы подумал о переименовании таблицы.

Комментарии:

1. Я рассматриваю ваше предложение сделать две строки как одну. Могу ли я узнать, как я могу работать над этим? Спасибо

2. Можно иметь две строки, если вы этого хотите, однако нам нужно знать логику, стоящую за этим (например, одна строка предназначена для всех отрицательных транзакций, а другая — для всех положительных транзакций. Вам также необходимо подтвердить, что ни одна строка не может иметь как отрицательные, так и положительные значения для разных полей). Посмотрите, как вы можете работать над этим — я предлагаю прочитать о GROUP BY и попробовать разные вещи с вышеизложенным. Если вам нужно 2 строки на транзакцию, потребуется немного более сложный фрагмент кода (например, вам нужно будет пометить строки как положительные или отрицательные, а затем сгруппировать по ним)

3. к сожалению, когда в тендерах есть сумма (cash и gc), сумма удваивалась в зависимости от количества элементов. например, у меня есть 2 товара, а общий объем продаж составляет 500, когда дело доходит до наличных денег, он стал 1000, будет ли в любом случае, что я все еще могу сделать это в одной строке?