2017-02-13 10 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 | 
+------------+-----------+-----------+------------+--------------+ 

は以下のとおりです。family_idによって

  • グループ(だから我々は2つのグループを持つことになります)
  • 各グループについて、存在する場合is_primaryの行が1に等しい場合は、それらのランダムな行を選択し、グループの2つの列の出力としてfirst_nameとlast_nameを取得します。
  • is_primaryと等しい行がない場合図1に示すように、行を見つけるis_secondaryが1に等しく、グループの二つの列の出力としてのFIRST_NAMEと姓を得る有する(任意の行がOKである)
  • ので、上記説明した論理とデータ、正確に基づく

結果は次のようになります。

+-----------+------------+-----------+ 
| 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

最初の結果が必要な場合は、簡単に使用してください:use family_id、min(first_name)、min(last_name) from mytable group_id by –

答えて

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(&挿入するスクリプトを作成するためのおかげで):OPコメント1として を(両方のフラグが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節のない選択は、本質的に非決定的ですが、あなたは同意しませんか?さまざまなレベルの「ランダム性」と異なる関連コストを持つ「ランダム」と「ランダム」があることに注意してください。ちなみに、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

それはあなたの具体的な質問、ちょうど観測への答えではありません。このようなロジックを持つソフトウェアやWebアプリケーションを開発しなければならない場合は、SQLから使用可能なプログラミング言語に移行します。興味のあるデータセットを取得し、スキャンし、グループ分けしてソートします。

関連する問題