SQL: закрепленные строки и вычисление номера строки - PullRequest
0 голосов
/ 14 декабря 2018

У нас есть требование назначить номер строки всем строкам, используя следующее правило

  • Строка, если закрепленный должна иметь тот же номер строки
  • В противном случае сортировать его по GMD

Пример:

 ID  GMD   IsPinned 

 1   2.5    0        
 2    0     1        
 3    2     0        
 4    4     1        
 5    3     0       

Следует выводить

ID  GMD   IsPinned  RowNo

5    3    0          1   
2    0    1          2  
1    2.5  0          3  
4    4    1          4  
3    2    0          5  

Обратите внимание, что номер строки для идентификаторов 2 и 4 остался без изменений, поскольку они закреплены значениями 2 и 4 соответственно, хотяGMD расположены не в любом порядке. Остальные строки Идентификационные номера 1, 3 и 5 строк сортируются с использованием GMD. desc

Я пытался использовать RowNumber SQL 2012, однако он выталкивает закрепленные элементы с их позиции

Ответы [ 4 ]

0 голосов
/ 14 декабря 2018

Вот основанный на множестве подход к решению этой проблемы.Обратите внимание, что первый CTE не нужен, если в вашей базе данных уже есть таблица Numbers:

declare @t table (ID int,GMD decimal(5,2),IsPinned bit)
insert into @t (ID,GMD,IsPinned) values
(1,2.5,0), (2, 0 ,1), (3, 2 ,0), (4, 4 ,1), (5, 3 ,0)

;With Numbers as (
    select ROW_NUMBER() OVER (ORDER BY ID) n from @t
), NumbersWithout as (
    select
        n,
        ROW_NUMBER() OVER (ORDER BY n) as rn
    from
        Numbers
    where n not in (select ID from @t where IsPinned=1)
), DataWithout as (
    select
        *,
        ROW_NUMBER() OVER (ORDER BY GMD desc) as rn
    from
        @t
    where
        IsPinned = 0
)
select
    t.*,
    COALESCE(nw.n,t.ID) as RowNo
from
    @t t
        left join
    DataWithout dw
        inner join
    NumbersWithout nw
        on
            dw.rn = nw.rn
        on
            dw.ID = t.ID
order by COALESCE(nw.n,t.ID)

Надеюсь, мое наименование прояснит, что мы делаем.Я немного дерзкий в последнем SELECT, используя COALESCE, чтобы получить окончательный RowNo, когда вы, возможно, ожидали выражение CASE.Но это работает, потому что содержимое DataWithout CTE определено так, что оно существует только для неподкрепленных элементов, что приводит к сбою окончательного LEFT JOIN.

Результаты:

ID          GMD                                     IsPinned RowNo
----------- --------------------------------------- -------- --------------------
5           3.00                                    0        1
2           0.00                                    1        2
1           2.50                                    0        3
4           4.00                                    1        4
3           2.00                                    0        5

Секундавариант, который может работать лучше (но никогда не предполагать, всегда тестировать):

declare @t table (ID int,GMD decimal(5,2),IsPinned bit)
insert into @t (ID,GMD,IsPinned) values
(1,2.5,0), (2, 0 ,1), (3, 2 ,0), (4, 4 ,1), (5, 3 ,0)

;With Numbers as (
    select ROW_NUMBER() OVER (ORDER BY ID) n from @t
), NumbersWithout as (
    select
        n,
        ROW_NUMBER() OVER (ORDER BY n) as rn
    from
        Numbers
    where n not in (select ID from @t where IsPinned=1)
), DataPartitioned as (
    select
        *,
        ROW_NUMBER() OVER (PARTITION BY IsPinned ORDER BY GMD desc) as rn
    from
        @t
)
select
    dp.ID,dp.GMD,dp.IsPinned,
    CASE WHEN IsPinned = 1 THEN ID ELSE nw.n END as RowNo
from
    DataPartitioned dp
        left join
    NumbersWithout nw
        on
            dp.rn = nw.rn
order by RowNo

В третьем CTE, введя PARTITION BY и удалив предложение WHERE, мы гарантируем, что у нас есть все строки данных, так чтонам не нужно повторно присоединяться к исходной таблице в конечном результате в этом варианте.

0 голосов
/ 14 декабря 2018

Можете ли вы попробовать этот запрос

CREATE TABLE Table1
    (ID int, GMD numeric (18,2), IsPinned int);


INSERT INTO Table1 (ID,GMD, IsPinned)
         VALUES (1, 2.5, 0), 
                (2, 0, 1),
                (3, 2, 0),
                (4, 4, 1),
                (5, 3, 0)





   select *, row_number () over(partition by IsPinned order by (case when IsPinned =0 then GMD else id end) ) [CustOrder] from Table1

Result

0 голосов
/ 14 декабря 2018

Это заняло больше времени, чем я думал, дело в том, что row_number примет участие, чтобы решить запрос.Нам нужно сначала дифференцировать row_numbers по id, а затем мы можем применить цикл while или курсор или любую итерацию, в нашем случае мы будем просто использовать цикл while.

dbo.test (вы можете заменитьпроверить с именем вашей таблицы)

1   2.5 False
2   0   True
3   3   False
4   4   True
6   2   False

Вот запрос, который я написал для достижения вашего результата. Я добавил комментарий к каждой операции, которую вы должны получить, если у вас есть какие-либо трудности, дайте мне знать.

Запрос :

--user data table 
DECLARE @userData TABLE 
  ( 
     id        INT NOT NULL, 
     gmd       FLOAT NOT NULL, 
     ispinned  BIT NOT NULL, 
     rownumber INT NOT NULL 
  ); 
--final result table 
DECLARE @finalResult TABLE 
  ( 
     id           INT NOT NULL, 
     gmd          FLOAT NOT NULL, 
     ispinned     BIT NOT NULL, 
     newrownumber INT NOT NULL 
  ); 

--inserting to uer data table from the table test 
INSERT INTO @userData 
SELECT t.*, 
       Row_number() 
         OVER ( 
           ORDER BY t.id ASC) AS RowNumber 
FROM   test t 

--creating new table for ids of not pinned 
CREATE TABLE #ids 
  ( 
     rn  INT, 
     id  INT, 
     gmd FLOAT 
  ) 

-- inserting into temp table named and adding gmd by desc
INSERT INTO #ids 
            (rn, 
             id, 
             gmd) 
SELECT DISTINCT Row_number() 
                  OVER( 
                    ORDER BY gmd DESC) AS rn, 
                id, 
                gmd 
FROM   @userData 
WHERE  ispinned = 0 

--declaring the variable to loop through all the no pinned items
DECLARE @id INT 
DECLARE @totalrows INT = (SELECT Count(*) 
   FROM   #ids) 
DECLARE @currentrow INT = 1 
DECLARE @assigningNumber INT = 1 

--inerting pinned items first
INSERT INTO @finalResult 
SELECT ud.id, 
       ud.gmd, 
       ud.ispinned, 
       ud.rownumber 
FROM   @userData ud 
WHERE  ispinned = 1 

--looping through all the rows till all non-pinned items finished
WHILE @currentrow <= @totalrows 
  BEGIN 
        --skipping pinned numers for the rows
      WHILE EXISTS(SELECT 1 
                   FROM   @finalResult 
                   WHERE  newrownumber = @assigningNumber 
                          AND ispinned = 1) 
        BEGIN 
            SET @assigningNumber = @assigningNumber + 1 
        END 

      --getting row by the number
      SET @id = (SELECT id 
                 FROM   #ids 
                 WHERE  rn = @currentrow) 

      --inserting the non-pinned item with new row number into the final result
      INSERT INTO @finalResult 
      SELECT ud.id, 
             ud.gmd, 
             ud.ispinned, 
             @assigningNumber 
      FROM   @userData ud 
      WHERE  id = @id       

      --going to next row
      SET @currentrow = @currentrow + 1 
      SET @assigningNumber = @assigningNumber + 1 
  END 

--getting final result
SELECT * 
FROM   @finalResult 
ORDER  BY newrownumber ASC 

--dropping table
DROP TABLE #ids 

Выход:

enter image description here

0 голосов
/ 14 декабря 2018

это будет работать:

CREATE TABLE Table1
    ("ID" int, "GMD" number, "IsPinned" int)
;

INSERT ALL 
    INTO Table1 ("ID", "GMD", "IsPinned")
         VALUES (1, 2.5, 0)
    INTO Table1 ("ID", "GMD", "IsPinned")
         VALUES (2, 0, 1)
    INTO Table1 ("ID", "GMD", "IsPinned")
         VALUES (3, 2, 0)
    INTO Table1 ("ID", "GMD", "IsPinned")
         VALUES (4, 4, 1)
    INTO Table1 ("ID", "GMD", "IsPinned")
         VALUES (5, 3, 0)
SELECT * FROM dual
;


select * from (select  "ID","GMD","IsPinned",rank from(select m.*,rank()over(order by 
"ID" asc) rank from Table1 m where "IsPinned"=1)
union
(select "ID","GMD","IsPinned",rank from (select t.*,rank() over(order by "GMD" 
desc)-1 rank from (SELECT * FROM Table1)t)
where "IsPinned"=0) order by "GMD" desc) order by rank ,GMD;

вывод:

   2    0   1   1
   5    3   0   1
   1    2.5 0   2
   4    4   1   2
   3    2   0   3
...