#mysql
#mysql
Вопрос:
Я хочу объединить несколько столбцов строк как одну запись в MySQL
Например: фактические данные
--------------------------------------------------------------
id name Loantype Amount
--------------------------------------------------------------
1 ABC 1 500000
2 ABC 2 3500000
3 XYZ 1 250000
4 XYZ 2 2500000
Я попытался со следующим запросом
SELECT
id,
(
CASE Loantype
WHEN 1 THEN Amount
ELSE NULL
END
) AS PersonalLoan,
(
CASE Loantype
WHEN 2 THEN Amount
ELSE NULL
END
) AS HomeLoan
FROM
customer
WHERE
name = 'ABC'
но результат выглядит следующим образом
--------------------------------------------------------------
id name PersonalLoan HomeLoan
--------------------------------------------------------------
1 ABC 500000 NULL
1 ABC NULL 2500000
Ожидаемый набор результатов
--------------------------------------------------------------
id name PersonalLoan HomeLoan
--------------------------------------------------------------
1 ABC 500000 3500000
Комментарии:
1. Что произойдет, если у одного и того же клиента есть несколько одинаковых кредитов
LoanType
? Или есть ограничение, чтобы этого не произошло?2. Какой столбец используется для объединения строк? Это имя?
3. @SoloOmsarashvili Нет
JOIN
необходимости.4. @Dai Как бы вы определили связь между двумя строками. Как я понял его случай, он хочет объединить строки, в которых дополнительные столбцы (PersonalLoan и HomeLoan) заполняются на основе LoanType
5. @SoloOmsarashvili Смотрите мой ответ, который не использует a
JOIN
, он использует aGROUP BY
.
Ответ №1:
Вы можете самостоятельно объединить таблицу, чтобы вы могли объединить 2 вида кредитов в одну строку:
SELECT t1.id, t1.name, t1.amount AS personal, t2.amount AS home
FROM customer AS t1
LEFT JOIN customer AS t2 ON t1.name = t2.name AND t2.loantype = 2
WHERE t1.loantype = 1
Если вы ищете только 1 пользователя — вы можете ускорить запрос, ограничив размер соединения:
SELECT t1.id, t1.name, t1.amount AS personal, t2.amount AS home
FROM (SELECT * FROM customer WHERE name = "ABC" AND loantype = 1) AS t1
LEFT JOIN customer AS t2 ON t1.name = t2.name AND t2.loantype = 2
Комментарии:
1. Ваш запрос не работает, если у клиента есть строки с
loantype = 2
, но нет ниloantype = 1
одной строки с. Он также вернетсяhome = NULL
вместоhome = 0
, если у клиента естьloantype = 1
, но не какие-либо строки сloantype = 2
(хотя в данном случае это может быть желательно).2. @Dai Вы правы. Но без достаточной информации в вопросе — мы можем только догадываться о потребностях или намерениях OP.
Ответ №2:
- Обратите внимание, что, вообще говоря, вы не должны денормализовать данные в SQL (например, преобразование строк в столбцы: SQL ориентирован на строки, а не на столбцы) — я предполагаю, что это упрощает логику отображения — просто будьте осторожны с использованием подобных запросов, когда вы хотите передать значимые данные в другие части базы данныха не напрямую пользователю.
GROUP BY
Сначала вам нужно.- Вы также можете упростить свои
CASE
выражения:ELSE NULL
всегда неявно, и еслиCASE WHEN
выражение представляет собой сравнение на равенство, вы можете использовать более простой синтаксис в стиле switch.- Так
CASE WHEN a = b THEN c ELSE NULL END
что можно упростить доCASE a WHEN b THEN c END
.
- Так
- Я добавил
COALESCE
, чтобы запрос возвращался0
дляSUM
агрегатов, если нет совпадающих строк вместоNULL
. Обратите внимание, чтоCOUNT
(в отличиеSUM
от) обычно не нужно заключать в aCOALESCE
(хотя я забыл, как именно MySQL обрабатывает это — это также зависит от того, какую версию MySQL вы используете и какие параметры строгого режима и соответствия ANSI / ISO включены).
- Обратите внимание, что опубликованный вами дизайн базы данных, похоже, позволяет одному и тому же
customer.name
иметь несколько одинаковых заимствованийloantype
.-
Вы можете избежать этого, добавив
UNIQUE CONSTRAINT
илиUNIQUE INDEX
или используя составной первичный ключ:CREATE UNIQUE INDEX UX_name_loantype ON customer ( name, loantype )
-
Чтобы эти строки не вызывали проблем в этом запросе, здесь используются a
SUM
и aCOUNT
, чтобы читателям было ясно, что данные являются совокупными по нескольким строкам:
-
SELECT
name,
COUNT( CASE Loantype WHEN 1 THEN 1 END ) AS CountPersonalLoans,
COALESCE( SUM( CASE Loantype WHEN 1 THEN Amount END ), 0 ) AS SumPersonalLoans,
COUNT( CASE Loantype WHEN 2 THEN 1 END ) AS CountHomeLoans,
COALESCE( SUM( CASE Loantype WHEN 2 THEN Amount END ), 0 ) AS SumHomeLoans
FROM
customer
GROUP BY
name
Чтобы максимизировать повторное использование кода запроса, если вы хотите фильтровать name
, преобразуйте это в VIEW
— или, если это одноразовый, сделайте его CTE
запросом, например:
WITH aggs AS (
SELECT
name,
COUNT( CASE Loantype WHEN 1 THEN 1 END ) AS CountPersonalLoans,
COALESCE( SUM( CASE Loantype WHEN 1 THEN Amount END ), 0 ) AS SumPersonalLoans,
COUNT( CASE Loantype WHEN 2 THEN 1 END ) AS CountHomeLoans,
COALESCE( SUM( CASE Loantype WHEN 2 THEN Amount END ), 0 ) AS SumHomeLoans
FROM
customer
GROUP BY
name
)
SELECT
name,
CountPersonalLoans,
SumPersonalLoans,
CountHomeLoans,
SumHomeLoans
FROM
aggs
WHERE
name = 'ABC'
ORDER BY
name
Комментарии:
1. РЕГИСТР без THEN не является допустимым синтаксисом.
2. @IVOGELOV Спасибо! Хороший улов. Исправление сейчас.