Take the 2-minute tour ×
Database Administrators Stack Exchange is a question and answer site for database professionals who wish to improve their database skills and learn from others in the community. It's 100% free, no registration required.

I have a stored procedure will be used to page through data. One of the requirements of the procedure is to have a parameter that will be used to sort two columns of data, the sorting should be used when applying the row_number().

Some sample data:

CREATE TABLE grp 
(
  [grp_id] uniqueidentifier primary key, 
  [grp_nm] varchar(5) not null, 
  [grp_owner] varchar(200) not null
);

INSERT INTO grp ([grp_id], [grp_nm], [grp_owner])
VALUES
    ('7F5F0F16-4EBE-E211-9C26-78E7D18E1E84', 'test1', 'me'),
    ('1F52A713-EFAC-E211-9C26-78E7D18E1E84', 'test2', 'me'),
    ('D123B48A-63AB-E211-9C26-78E7D18E1E84', 'test3', 'me'),
    ('48361F86-2BC2-E211-9C26-78E7D18E1E84', 'test4', 'me'),
    ('27429A57-93C1-E211-9C26-78E7D18E1E84', 'test5', 'me'),
    ('D5DF9F8E-EDC2-E211-9C26-78E7D18E1E84', 'test6', 'me'),
    ('9A07EA21-1AAD-E211-9C26-78E7D18E1E84', 'test7', 'me');


CREATE TABLE mbr
(
  [grp_id] uniqueidentifier, 
  [mbr_id] int not null primary key, 
  [acct_id] varchar(7) not null, 
  [cst] varchar(4) null
);

INSERT INTO mbr ([grp_id], [mbr_id], [acct_id], [cst])
VALUES
    ('7F5F0F16-4EBE-E211-9C26-78E7D18E1E84', 10, '1', 'AA'),
    ('7F5F0F16-4EBE-E211-9C26-78E7D18E1E84', 11, '2', 'BB'),
    ('1F52A713-EFAC-E211-9C26-78E7D18E1E84', 12, '1234578', 'blah'),
    ('D123B48A-63AB-E211-9C26-78E7D18E1E84', 13, '78', 'test'),
    ('48361F86-2BC2-E211-9C26-78E7D18E1E84', 14, 'x', 'mbr1'),
    ('48361F86-2BC2-E211-9C26-78E7D18E1E84', 15, 'a', 'mbr2'),
    ('27429A57-93C1-E211-9C26-78E7D18E1E84', 16, 'b', 'mbr1'),
    ('27429A57-93C1-E211-9C26-78E7D18E1E84', 17, 'c', 'mbr2'),
    ('D5DF9F8E-EDC2-E211-9C26-78E7D18E1E84', 18, 'a', 'mbr1'),
    ('9A07EA21-1AAD-E211-9C26-78E7D18E1E84', 19, 'a', 'mbr1');

The procedure and the sorting is currently working as written.

But an issue has cropped up with the way that we are applying the row_number(). The row_number() should almost simulate the ranking that occurs with dense_rank but it does not work as expected due to the sorting with the parameter.

For example, if I run the following query:

declare @sort_desc bit = 0

select g.grp_id, g.grp_nm,
    m.mbr_id, m.acct_id, m.cst,
    row_number() over(order by case when @sort_desc = 0 then g.grp_nm end
                              , case when @sort_desc = 0 then m.acct_id end
                              , case when @sort_desc = 1 then g.grp_nm end desc
                              , case when @sort_desc = 1 then m.acct_id end desc) rn,
    dense_rank()  over(order by case when @sort_desc = 0 then g.grp_nm end
                              , case when @sort_desc = 0 then m.acct_id end
                              , case when @sort_desc = 1 then g.grp_nm end desc
                              , case when @sort_desc = 1 then m.acct_id end desc) dr
from grp g
inner join mbr m
  on g.grp_id = m.grp_id;

See SQL Fiddle with Demo (a trimmed down stored proc is also present)

I get a result of:

|                               GRP_ID | GRP_NM | MBR_ID | ACCT_ID |  CST | RN | DR |
-------------------------------------------------------------------------------------
| 7F5F0F16-4EBE-E211-9C26-78E7D18E1E84 |  test1 |     10 |       1 |   AA |  1 |  1 |
| 7F5F0F16-4EBE-E211-9C26-78E7D18E1E84 |  test1 |     11 |       2 |   BB |  2 |  2 |
| 1F52A713-EFAC-E211-9C26-78E7D18E1E84 |  test2 |     12 | 1234578 | blah |  3 |  3 |
| D123B48A-63AB-E211-9C26-78E7D18E1E84 |  test3 |     13 |      78 | test |  4 |  4 |
| 48361F86-2BC2-E211-9C26-78E7D18E1E84 |  test4 |     15 |       a | mbr2 |  5 |  5 |
| 48361F86-2BC2-E211-9C26-78E7D18E1E84 |  test4 |     14 |       x | mbr1 |  6 |  6 |
| 27429A57-93C1-E211-9C26-78E7D18E1E84 |  test5 |     16 |       b | mbr1 |  7 |  7 |
| 27429A57-93C1-E211-9C26-78E7D18E1E84 |  test5 |     17 |       c | mbr2 |  8 |  8 |
| D5DF9F8E-EDC2-E211-9C26-78E7D18E1E84 |  test6 |     18 |       a | mbr1 |  9 |  9 |
| 9A07EA21-1AAD-E211-9C26-78E7D18E1E84 |  test7 |     19 |       a | mbr1 | 10 | 10 |

But the desired result is:

|                               GRP_ID | GRP_NM | MBR_ID | ACCT_ID |  CST | RN | expR|
-------------------------------------------------------------------------------------
| 7F5F0F16-4EBE-E211-9C26-78E7D18E1E84 |  test1 |     10 |       1 |   AA |  1 |  1  |
| 7F5F0F16-4EBE-E211-9C26-78E7D18E1E84 |  test1 |     11 |       2 |   BB |  2 |  1  |
| 1F52A713-EFAC-E211-9C26-78E7D18E1E84 |  test2 |     12 | 1234578 | blah |  3 |  2  |
| D123B48A-63AB-E211-9C26-78E7D18E1E84 |  test3 |     13 |      78 | test |  4 |  3  |
| 48361F86-2BC2-E211-9C26-78E7D18E1E84 |  test4 |     15 |       a | mbr2 |  5 |  4  |
| 48361F86-2BC2-E211-9C26-78E7D18E1E84 |  test4 |     14 |       x | mbr1 |  6 |  4  |
| 27429A57-93C1-E211-9C26-78E7D18E1E84 |  test5 |     16 |       b | mbr1 |  7 |  5  |
| 27429A57-93C1-E211-9C26-78E7D18E1E84 |  test5 |     17 |       c | mbr2 |  8 |  5  |
| D5DF9F8E-EDC2-E211-9C26-78E7D18E1E84 |  test6 |     18 |       a | mbr1 |  9 |  6  |
| 9A07EA21-1AAD-E211-9C26-78E7D18E1E84 |  test7 |     19 |       a | mbr1 | 10 |  7  |

As you can see the expR column values are incrementing based on the grp_id but the rows are still in the correct sort order. I am at a loss of how to get this result and any suggestions would be great.

share|improve this question
3  
+1 for amazing title. –  Zane May 22 '13 at 21:08
    
Is there a reason you want to use CASE rather than IF or dynamic SQL? –  Paul White May 22 '13 at 22:48
    
@PaulWhite This was a small piece of a stored proc. I trimmed down the details significantly to get a solution to this specific problem. I would be open to other suggestions/solutions. –  bluefeet May 22 '13 at 23:17
    
If your order by decisions are more complex, or if you have dynamic search criteria as well, it may be better to branch or to use dynamic SQL. You give SQL Server a better fighting chance optimizing the different variations separately then either (a) recompiling every time or (b) trying to find some magical, optimal plan that satisfies all the variations. –  Aaron Bertrand May 22 '13 at 23:40
    
@AaronBertrand The order by is exactly what I placed in this post. The stored proc has a large block of where filtering is used when the initial row_number is applied to the result. –  bluefeet May 22 '13 at 23:45

1 Answer 1

up vote 7 down vote accepted

This is about as concise as I could get it without squeezing my brain to disastrous effects. SQLFiddle.

DECLARE @sort_desc BIT = 0;

;WITH x AS
(
  SELECT g.grp_id, g.grp_nm, m.mbr_id, m.acct_id, m.cst,
    o1 = ROW_NUMBER() OVER (ORDER BY 
         CASE @sort_desc WHEN 0 THEN g.grp_nm END,
         CASE @sort_desc WHEN 0 THEN m.acct_id END,
         g.grp_nm DESC, m.acct_id DESC)
  FROM dbo.grp AS g
  INNER JOIN dbo.mbr AS m
  ON g.grp_id = m.grp_id
), 
y AS
(
  SELECT *, o2 = ROW_NUMBER() OVER (PARTITION BY grp_id ORDER BY o1)
  FROM x
)
SELECT *, expected = DENSE_RANK() OVER (ORDER BY o1-o2)
FROM y
ORDER BY o1;

You'll of course want to extrapolate out all the * references to the actual columns you need to carry forward and ultimately output. I'm lazy but do as I say, not as I do. :-)

share|improve this answer
    
Well of course this appears to be working, I just need to test it a bit more with the entire proc. –  bluefeet May 22 '13 at 21:31

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.