簡體   English   中英

ROW_NUMBER()顯示意外值

[英]ROW_NUMBER() shows unexpected values

我的表具有類似的值( RowCount由下面的查詢生成):

ID       Date_trans   Time_trans  Price  RowCount
-------  -----------  ----------  -----  --------
1699093  22-Feb-2011  09:30:00    58.07  1
1699094  22-Feb-2011  09:30:00    58.08  1
1699095  22-Feb-2011  09:30:00    58.08  2
1699096  22-Feb-2011  09:30:00    58.08  3
1699097  22-Feb-2011  09:30:00    58.13  1
1699098  22-Feb-2011  09:30:00    58.13  2
1699099  22-Feb-2011  09:30:00    58.12  1
1699100  22-Feb-2011  09:30:08    58.13  3
1699101  22-Feb-2011  09:30:09    57.96  1
1699102  22-Feb-2011  09:30:09    57.95  1
1699103  22-Feb-2011  09:30:09    57.93  1
1699104  22-Feb-2011  09:30:09    57.96  2
1699105  22-Feb-2011  09:30:09    57.93  2
1699106  22-Feb-2011  09:30:09    57.93  3
1699107  22-Feb-2011  09:30:37    58     1
1699108  22-Feb-2011  09:30:37    58.08  4
1699109  22-Feb-2011  09:30:38    58.08  5
1699110  22-Feb-2011  09:30:41    58.02  1
1699111  22-Feb-2011  09:30:41    58.02  2
1699112  22-Feb-2011  09:30:41    58.01  1
1699113  22-Feb-2011  09:30:41    58.01  2
1699114  22-Feb-2011  09:30:41    58.01  3
1699115  22-Feb-2011  09:30:42    58.02  3
1699116  22-Feb-2011  09:30:42    58.02  4
1699117  22-Feb-2011  09:30:45    58.04  1
1699118  22-Feb-2011  09:30:54    58     2
1699119  22-Feb-2011  09:30:57    58.05  1

ID列是IDENTITY列。
我正在使用此查詢來獲取連續的行計數為:

  SELECT   ID, Date_trans, Time_trans, Price
          ,ROW_NUMBER() OVER(PARTITION BY Price  ORDER BY ID) RowCount
  FROM     MyTable
  ORDER    BY ID;

我得到的RowCount適用於大多數值,但不適用於某些值。 例如:

  • ID 1699100價格58.13 –計數應為1(顯示3)。
  • ID 1699104價格57.96 –計數應為1(顯示2)。
  • ID 1699105,1699106價格57.93 –計數應為1、2(顯示2、3)。

我在PostgreSQL中嘗試了相同的查詢,並找到了相同的結果。
在這里上傳了一個csv數據示例

我被分區的這種意外結果所困擾。 有誰能夠幫助我?

ROW_NUMBER()函數的PARTITION BY子句指示它對由Price值設置的整個行進行分區,並以ID的升序分配行號。

似乎您想區分具有相同Price值的任何兩組行,這些行之間至少由具有不同Price一行分隔開

可能有多種方法可以實現這一目標。 在SQL Server中(我認為同樣適用於PostgreSQL),我將首先使用兩個ROW_NUMBER()調用來獲取附加的分區條件,然后使用該條件再次對行進行排名,如下所示:

WITH partitioned AS (
  SELECT
    ID,
    Date_trans,
    Time_trans,
    Price,
    ROW_NUMBER() OVER (                   ORDER BY ID) -
    ROW_NUMBER() OVER (PARTITION BY Price ORDER BY ID) AS PriceGroup
  FROM MyTable
)
SELECT
  ID,
  Date_trans,
  Time_trans,
  Price,
  ROW_NUMBER() OVER (PARTITION BY Price, PriceGroup ORDER BY ID) AS RowCount
FROM partitioned
ORDER BY ID
;

這是一個SQL Fiddle演示

純SQL

WITH x AS (
    SELECT id, date_trans, time_trans, price
         ,(price <> lag(price) OVER (ORDER BY id))::int AS step
    FROM   tbl
    )
    ,y AS (
    SELECT *, sum(step) OVER (ORDER BY id) AS grp
    FROM   x
    )
SELECT id, date_trans, time_trans, price
      ,row_number() OVER (PARTITION BY grp ORDER BY id) As row_ct
FROM   y
ORDER  BY id;

邏輯:

  1. 請記住,與step的最后一行相比,價格何時發生變化。 (第一行的特殊情況也適用。)
  2. 總結步驟,以使相同的價格依次出現在同一組grp
  3. 每組行數。

老實說,我認為@Andriy的解決方案稍微優雅一點。 它也需要三個窗口函數,但是只能在兩個查詢步驟中完成。 在對小樣品的快速測試中,它的速度也稍快一些。 因此,我+1。

如果性能至關重要,那么使用

PL / pgSQL函數

應該會更快,因為它只需要掃描和排序表一次。

CREATE OR REPLACE FUNCTION f_my_row_ct()
  RETURNS TABLE (
    id         int
   ,date_trans date
   ,time_trans time
   ,price      numeric
   ,row_ct     int
  ) AS
$BODY$
DECLARE
   _last_price numeric;   -- remember price of last row
BEGIN

FOR id, date_trans, time_trans, price IN 
   SELECT t.id, t.date_trans, t.time_trans, t.price
   FROM   tbl t
   ORDER  BY t.id
LOOP
   IF _last_price = price THEN   -- works with 1st row, too
      row_ct := row_ct + 1;
   ELSE
      row_ct := 1;
   END IF;

   RETURN NEXT;
   _last_price = price;   -- remember last price
END LOOP;

END;
$BODY$  LANGUAGE plpgsql;

呼叫:

SELECT * FROM f_my_row_ct()

在對小樣本進行的另一項快速測試中,速度提高了3-4倍。 使用EXPLAIN ANALYZE進行測試以查看。


date_trans date :您可以通過將date_trans datetime_trans time合並到ts_trans timestamp來簡化表(和查詢)並節省一些存儲字節。

使用timestamptimestamp提取datetime非常簡單且非常快速:

ts_trans::date
ts_trans::time

關於日期/時間類型的手冊。

  • 1699100價格58.0-顯示3因為1699097,8是1,2

  • 1699104價格57.96 –顯示2,因為1669101為1。

  • 1699105,1699106價格57.93 –顯示2、3,因為1699103是1

如果要在序列中查找具有相同值的項目,一種選擇是將數據連接到先前的ID,並查看值是否相同

根據您對結果的期望,我可以收集到的信息,您也需要對Time_trans進行分區:

  SELECT   ID, Date_trans, Time_trans, Price
           ,ROW_NUMBER() OVER(PARTITION BY Time_trans, Price ORDER BY ID) RowCount
  FROM     MyTable
  ORDER BY ID

我認為是這種情況,因為您希望當時間轉換值隨着數據的處理而變化時,ROW_NUMBER重新開始。

另外,如果表中可能有多個日期,您可能也想在其中添加Date_trans,這是我期望的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM