2017-02-13 7 views
2

У меня есть кусок данных:(SQL) Как выбрать правильную строку для каждой группы?

+------------+-----------+-----------+------------+--------------+ 
| first_name | last_name | family_id | is_primary | is_secondary | 
+------------+-----------+-----------+------------+--------------+ 
| a   | b   |   1 |   1 |   0 | 
| aa   | bb  |   1 |   0 |   0 | 
| c   | d   |   1 |   0 |   0 | 
| cc   | dd  |   1 |   0 |   0 | 
| e   | f   |  10 |   0 |   0 | 
| e   | f   |  10 |   0 |   1 | 
| gg   | hh  |  10 |   0 |   1 | 
| gg   | hh  |  10 |   0 |   0 | 
| gg   | hh  |  10 |   0 |   0 | 
| gg   | hh  |  10 |   0 |   0 | 
+------------+-----------+-----------+------------+--------------+ 

То, что я хочу сделать являются:

  • Group по family_id (Таким образом, мы имеем две группы)
  • Для каждой группы, если есть некоторые строки, которые имеют is_primary, равны 1, затем выбирают из них случайную строку и получают ее имя_ first_name и last_name как вывод из двух столбцов группы.
  • Для каждой группы, если нет строки, которая имеет is_primary равно 1, найти строку (любая строка в порядке), который имеет is_secondary равен 1 и получить его first_name и last_name как выход двух колонок группы

Так на основе логики, описанной выше, и данных, правильно результат должен быть:

+-----------+------------+-----------+ 
| family_id | first_name | last_name | 
+-----------+------------+-----------+ 
|   1 | a   | b   | 
|  10 | e   | f   | 
+-----------+------------+-----------+ 

Или

+-----------+------------+-----------+ 
| family_id | first_name | last_name | 
+-----------+------------+-----------+ 
|   1 | a   | b   | 
|  10 | gg   | hh  | 
+-----------+------------+-----------+ 

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

Ниже приведен сценарий для создания тестовой таблицы.

USE tempdb 
GO 
IF OBJECT_ID('dbo.mytable') IS NOT NULL DROP TABLE dbo.mytable; 
CREATE TABLE mytable (
    first_name VARCHAR(2) NOT NULL, 
    last_name VARCHAR(2) NOT NULL, 
    family_id INTEGER NOT NULL, 
    is_primary INTEGER NOT NULL, 
    is_secondary INTEGER NOT NULL); 

INSERT INTO mytable VALUES ('a','b',1,1,0); 
INSERT INTO mytable VALUES ('aa','bb',1,0,0); 
INSERT INTO mytable VALUES ('c','d',1,0,0); 
INSERT INTO mytable VALUES ('cc','dd',1,0,0); 
INSERT INTO mytable VALUES ('e','f',10,0,0); 
INSERT INTO mytable VALUES ('e','f',10,0,1); 
INSERT INTO mytable VALUES ('gg','hh',10,0,1); 
INSERT INTO mytable VALUES ('gg','hh',10,0,0); 
INSERT INTO mytable VALUES ('gg','hh',10,0,0); 
INSERT INTO mytable VALUES ('gg','hh',10,0,0); 
GO 

SELECT * FROM dbo.mytable; 
+0

что вы пробовали –

+0

Да, я попытался решить проблему, но не смог. Позвольте мне уточнить вопрос. –

+0

Если вы хотите получить первый результат, то он не требует каких-либо усилий, просто используйте его: выберите family_id, min (first_name), min (last_name) from mytable group by family_id –

ответ

2

Попробуйте этот подход:

;with x as (
    select *, row_number() over(partition by family_id order by is_primary desc, is_secondary desc) rn 
    from mytable 
    where is_primary+is_secondary = 1 
) 
select * from x where rn = 1 

(спасибо за вставки сценария создают &)

EDIT: В соответствии с ОП комментарий (что оба флага может быть 1), изменить WHERE пункт

where is_primary = 1 or (is_primary = 0 and is_secondary = 1) 
+0

Поскольку 'OP' упоминает' is_primary' и 'is_secondary' может оба 1, условие where необходимо изменить как'> = '1 – Eric

+0

Также не выбирая случайным образом (вы можете просто заказать что-то недетерминированное, например RAND) – Caleth

+0

@ Caleth Любой выбор без явного предложения ORDER BY не является детерминированным по своей природе, вы не согласны? Имейте в виду, что есть «случайные» и «случайные», с разными уровнями «случайности» и различной связанной стоимостью. BTW, RAND() не является случайным вообще, CHECKSUM (NEWID()) будет здесь лучше. – dean

1

Если выбранные строки должны быть b e, затем используйте следующее:

WITH primary_families AS (
    SELECT family_id 
      ,first_name 
      ,last_name 
      ,ROW_NUMBER() OVER(ORDER BY NEWID()) AS r 
    FROM familytable 
    WHERE is_primary = 1 
), 
secondary_families AS (
    SELECT family_id 
      ,first_name 
      ,last_name 
      ,ROW_NUMBER() OVER(ORDER BY NEWID()) AS r 
    FROM familytable f 
    WHERE is_secondary = 1 
    AND NOT EXISTS (
     SELECT 1 
     FROM familytable 
     WHERE family_id = f.family_id 
     AND is_primary = 1 
    ) 
) 

SELECT f.family_id 
     ,f.first_name 
     ,f.last_name 
FROM primary_families f 
WHERE f.r = 1 

UNION 

SELECT f.family_id 
     ,f.first_name 
     ,f.last_name 
FROM secondary_families f 
WHERE f.r = 1 
0

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

Смежные вопросы