#sql #postgresql #postgresql-9.6
Вопрос:
У меня есть такой столик:
cms_code | product
------------ ---------
55381XA384 | MS
55381XA384 | MS
55381XA384 | HSD
55381XA384 | HSD
55381XA382 | HSD
55381XA382 | XP
55381XA382 | MS
55381XA382 | HSD
55381XA382 | HSD
Теперь мне нужен такой результат, как этот:
cms_code | product
------------ ---------
55381XA384 | MS
NULL | MS
NULL | HSD
NULL | HSD
55381XA382 | HSD
NULL | XP
NULL | MS
NULL | HSD
NULL | HSD
Комментарии:
1. Почему вы отметили свой вопрос с помощью MySQL и Microsoft SQL Server, если вы используете PostgreSQL?
Ответ №1:
Ваши результаты зависят от порядка строк. Таблицы SQL представляют собой неупорядоченные наборы, поэтому вы не можете делать то, что хотите, с имеющимися у вас данными.
Предполагая, что у вас есть столбец, в котором указан порядок, вы могли бы сделать:
select (case when row_number() over (partition by cms_code order by <ordering col< = 1
then cms_code
end) as cms_code, product_code
from t
order by cms_code, <ordering col>;
Без столбца заказа вы также можете сделать:
with cte as (
select t.*, row_number() over (partition by cms_code order by cms_code) as seqnum
from t
)
select (case when seqnum = 1 then cms_code end) as cms_code,
product_code
from t
order by cms_code, seqnum;
В обоих случаях вам нужно указать order by
во внешнем запросе, чтобы гарантировать, что результирующий набор упорядочен таким образом, чтобы «первая» строка содержала cms_code
.
Ответ №2:
вы можете использовать оконные функции для нумерации строк и установки последующих значений null
, сохраняя значение cms_code
только для строки № 1.
select
case
when row_number() over (partition by cms_code) = 1 then cms_code
else null
end cms_code
, product_code
from my_table
order by cms_code
Комментарии:
1. @KaranChaudhari . . . Нет, это не «работает идеально». Может показаться, что это работает, но без стабильности
order by
во внешнем запросе результирующий набор не имеет гарантированного порядка.2. @GordonLinoff, будет
row_number() over (partition by cms_code order by cms_code)
производить нумерацию строк , которая более стабильна, чемrow_number() over (partition by cms_code)
, и почему3. @HaleemurAli …. Нет , просто некоторые базы данных (и стандарт) требуют
order by
этого, поэтому я обычно просто включаю это.
Ответ №3:
Я предполагаю, что вы хотите, чтобы значение null для всех значений cms_code было одинаковым после первого значения. Поправьте меня, если я ошибаюсь, Приведенный ниже запрос может быть использован для того же:
SELECT
CASE
WHEN ROW_NUMBER() OVER(PARTITION BY cms_code order by product) = 1
THEN NULL
ELSE cms_code
END AS cms_code,product
FROM table;