PARTITION BY значение строки - PullRequest
0 голосов
/ 19 февраля 2020

Мне нужно разделить мою выходную таблицу, когда определенная строка имеет определенное значение. У меня есть:

ID|Value|User
-------------
1 |A    |Rick
2 |A    |Rick
3 |B    |Rick
7 |A    |Rick
8 |C    |Rick
4 |A    |Joe
5 |B    |Joe
6 |B    |Joe

Мне нужно разделить свою таблицу для каждого отдельного пользователя, и когда значение = A, так что мне нужно:

Row|ID|Value|User
------------------
1  |1 |A    |Rick 
1  |2 |A    |Rick
2  |3 |B    |Rick
1  |7 |A    |Rick
2  |8 |C    |Rick
1  |4 |A    |Joe
2  |5 |B    |Joe
3  |6 |B    |Joe

Каждое значение имеет свое ID.

Я пробовал что-то вроде:

SELECT ROW_NUMBER() OVER(PARTITION BY User, Value = A ORDER BY ID ASC) AS Row, Value, User FROM...
SELECT ROW_NUMBER() OVER(PARTITION BY User, WHERE Value = A ORDER BY ID ASC) AS Row, Value, User FROM...
etc

Но я не могу понять, как правильно написать, если это вообще возможно.

Ответы [ 4 ]

1 голос
/ 19 февраля 2020

Похоже, что вы ищете просто DENSE_RANK:

DENSE_RANK() OVER (PARTITION BY [User] ORDER BY [Value] ASC) AS [Row]

Примечание USER - зарезервированное ключевое слово в T- SQL. Я настоятельно рекомендую вам выбрать другое имя для своего столбца, так как в противном случае вы должны разделить его. ROW и VALUE в настоящее время не зарезервированы, но они перечислены как Future Keyword , и их также рекомендуется избегать.

Редактировать: Кажется, на самом деле что 'A' равно 1, а затем также увеличивается. Это грязно, но вы можете сделать следующее:

SELECT CASE [Value]
            WHEN 'A' THEN 1
            ELSE ROW_NUMBER() OVER (PARTITION BY [User] ORDER BY [Value]) -
                 COUNT(CASE [Value] WHEN 'A' THEN 1 END) OVER (PARTITION BY [User]) + 1
       END AS [Row],
       V.[Value],
       V.[User]
FROM (VALUES ('A', 'Rick'),
             ('A', 'Rick'),
             ('B', 'Rick'),
             ('C', 'Rick'),
             ('A', 'Joe '),
             ('B', 'Joe '),
             ('B', 'Joe ')) V ([Value], [User]);

Это предполагает , что всегда будет хотя бы одна строка с 'A'.

Править 2: Хорошо, сообщения цели были перемещены снова, это теперь делает то, что вы после. Если они переместятся снова, вам нужно будет изменить решение, хотя:

WITH YourTable AS(
    SELECT V.ID,
           V.Value,
           V.[User]
    FROM (VALUES(1,'A','Rick'),
                (2,'A','Rick'),
                (3,'B','Rick'),
                (7,'A','Rick'),
                (8,'C','Rick'),
                (4,'A','Joe '),
                (5,'B','Joe '),
                (6,'B','Joe '))V(ID,[Value],[User])),
Grps AS(
    SELECT YT.ID,
           YT.Value,
           YT.[User],
           COUNT(CASE YT.[Value] WHEN 'A' THEN 1 END) OVER(PARTITION BY YT.[User] ORDER BY YT.ID) AS Grp
    FROM YourTable YT)
SELECT ID,
       CASE G.[Value]
            WHEN 'A' THEN 1
            ELSE ROW_NUMBER() OVER (PARTITION BY G.[User], G.Grp ORDER BY G.[Value]) -
                 COUNT(CASE G.[Value] WHEN 'A' THEN 1 END) OVER (PARTITION BY G.[User], G.Grp) + 1
       END AS [Row],
       G.[Value],
       G.[User]
FROM Grps G
ORDER BY G.[User], G.ID;
0 голосов
/ 19 февраля 2020

Я не думаю, что DENSE_RANK() будет работать, как в вашем примере B будет иметь то же значение

2  |B    |Joe
2  |B    |Joe

вместо

2  |B    |Joe
3  |B    |Joe

Лучший способ, которым я ' Мы придумаем двухпроходный метод

  1. Использовать обычный ROW_NUMBER() -> ROW_NUMBER() OVER (PARTITION BY c.name ORDER BY c.value) AS rn
  2. Затем используйте DENSE_RANK() -> DENSE_RANK() OVER (PARTITION BY c.name ORDER BY IIF(c.value = 'a', NULL, c.rn))
  3. Хитрость здесь в том, что ORDER BY, где мы обнуляем его, исходя из условия IIF(c.value = 'a', NULL, c.rn))
WITH 
    cte_dataset ([value], [name])
  AS (SELECT 'A' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'A' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'B' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'C' AS v, 'Rick' AS n
      UNION ALL
      SELECT 'A' AS v, 'Joe' AS n
      UNION ALL
      SELECT 'B' AS v, 'Joe' AS n
      UNION ALL
      SELECT 'B' AS v, 'Joe' AS n)
   , cte_add_simple_order
  AS (
    SELECT 
        c.value, 
        c.name, 
        ROW_NUMBER() OVER (PARTITION BY c.name ORDER BY c.value) AS rn 
    FROM cte_dataset c
    )
SELECT
    c.value
  , c.name
  , DENSE_RANK() OVER (PARTITION BY c.name ORDER BY IIF(c.value = 'a', NULL, c.rn))
FROM cte_add_simple_order c
ORDER BY
    c.name DESC
  , c.value ;
|value|name|Rank|
|A    |Rick|1   |
|A    |Rick|1   |
|B    |Rick|2   |
|C    |Rick|3   |
|A    |Joe |1   |
|B    |Joe |2   |
|B    |Joe |3   |
0 голосов
/ 19 февраля 2020
DECLARE @Table AS TABLE
(
    RowNumber   INT
    ,[Value]    CHAR(5)
    ,[User]     VARCHAR(10)
)

INSERT INTO @Table
(
    [Value]
    ,[User]
)
values
 ('A','Rick') 
,('A','Rick')
,('B','Rick')
,('C','Rick')
,('A','Joe ')
,('B','Joe ')
,('B','Joe ')


    select 
        RowNumber       = DENSE_RANK() OVER(PARTITION BY [User] ORDER BY [Value] ASC) 
        ,[User]
        ,[Value]
    from 
        @Table
    WHERE
        [Value] = 'A'
UNION ALL
    select 
        RowNumber       = ROW_NUMBER() OVER(PARTITION BY [User] ORDER BY [Value] ASC)  + 1
        ,[User]
        ,[Value]
    from 
        @Table
    WHERE
        [Value] != 'A'
    Order BY
        [User] DESC
0 голосов
/ 19 февраля 2020

Как насчет этого - A всегда равно 1, я возвращаюсь к 1, если появляется A, тогда я всегда увеличиваю на 1, если это не A

With CTE AS (select *, row_number() OVER (order by [user], value) as RN from theTable)

select CASE WHEN C1.Value = 'A' THEN 1 ELSE 1 +  C1.RN - C.RN  END [row] ,  * from 
            CTE C1 OUTER APPLY 
              (SELECT TOP 1 RN FROM CTE C2 
                                WHERE C2.RN < C1.RN AND C2.Value = 'A' 
                                ORDER BY C2.RN DESC) C
...