简体   繁体   中英

Getting a distinct code-name pair but sorting on other columns

I'm a bit stumped on writing a query (SQL not my strong point).

Say I have the following TABLE1 :

CODE NAME     SCOPE1  SCOPE2    SEQ
------------------------------------
A    a        Here              1
B    b        Here              2
C    c        Here              3
C    c                Room      1
A    aa               Room      2
B    bbb              Room      3

The business key is CODE + SCOPE1 + SCOPE2 , where SCOPE1 and SCOPE2 are always mutually exclusive.

How can I get a distinct result of CODE and NAME given that I need sort by SCOPE1 , SCOPE2 , and SEQ ?

That is, given SCOPE1 = 'Here' and SCOPE2 = 'Room' , I would like to get this result:

CODE NAME
---------
A    a
B    b
C    c
A    aa
B    bbb

Note: C c from Room is not wanted as it's a duplicate to C c from Here .

I do realise the limitation of using DISTINCT with ORDER BY and the best I could come up with was the following:

select distinct CODE, NAME from
(
    select CODE, NAME from MYTABLE
    where (SCOPE1='Here' or SCOPE2='Room')
    order by SCOPE1, SCOPE2, SEQ
);

The above produces the correct pairs but in the wrong sequence. I tried messing around with GROUP BY , but I guess I didn't know enough.

I have to stick with standard SQL (that is, no product-specific SQL constructs, unless it's Oracle, maybe), and I guess with this particular query, it's probably impossible to avoid subselects.

I would be very grateful for any pointers. Thanks in advance.

UPDATE: I've updated the data set, and based on peterm's answer, here's what I have so far: sqlfiddle . The MIN/MAX trick doesn't work well when I start tweaking the sequences.

The assumption is that I will always search for one specific SCOPE1 paired with one specific SCOPE2 . But I need all SCOPE1 records to appear before SCOPE2 . The idea is that I don't care whether CODE + NAME comes from SCOPE1 or SCOPE2 - I just want unique pairs that are sorted by SCOPE1 , SCOPE2 , and SEQ .

UPDATE Based on your updated requirements for Oracle

SELECT CODE, NAME
  FROM
(
  SELECT CODE, NAME, 
         ROW_NUMBER() OVER (ORDER BY SCOPE1, SCOPE2, SEQ) rnum
    FROM Table1
   WHERE SCOPE1='Here' 
      OR SCOPE2='Room'
) q 
 GROUP BY CODE, NAME
 ORDER BY MIN(rnum)

Here is SQLFiddle

To make it work the same way in SQL Server

SELECT CODE, NAME
  FROM
(
  SELECT CODE, NAME, 
         ROW_NUMBER() OVER (ORDER BY CASE WHEN SCOPE1 IS NULL 
                                          THEN 1 ELSE 0 END, SCOPE1,
                                     CASE WHEN SCOPE2 IS NULL 
                                          THEN 2 ELSE 3 END, SCOPE2, SEQ) rnum
    FROM Table1
   WHERE SCOPE1='Here' 
      OR SCOPE2='Room'
) q 
 GROUP BY CODE, NAME
 ORDER BY MIN(rnum)

Here is SQLFiddle

Output:

| CODE | NAME |
---------------
|    A |    a |
|    B |    b |
|    C |    c |
|    A |   aa |
|    B |  bbb |

Original answer: The only thing I could think of based on your description of requirements

SELECT CODE, NAME
  FROM Table1
 WHERE SCOPE1='Here' 
    OR SCOPE2='Room'
 GROUP BY CODE, NAME
 ORDER BY MIN(SCOPE1), MIN(SCOPE2), MIN(SEQ)

Here is SQLFiddle demo (MySql)
Here is SQLFiddle demo (SQL Server)
Here is SQLFiddle demo (Oracle)

Now in MySql and SQL Server NULL s go first by default therefore you'll get

| CODE | NAME |
---------------
|    B |  bbb |
|    A |    a |
|    B |    b |
|    C |    c |

In Oracle NULL s go last by default therefore you'll get

| CODE | NAME |
---------------
|    A |    a |
|    B |    b |
|    C |    c |
|    B |  bbb |

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM