我的表中有值一样( 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数据样本 。
我坚持分区的这种意想不到的结果。 有谁能够帮助我?
的PARTITION BY
的条款ROW_NUMBER()
函数指示它整个行通过设置划分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小提琴演示 。
纯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;
逻辑:
- 当价格变化相比,在最后一排记住
step
。 (第一行的特殊情况也可实现此。) - 综上所述步骤,以使得相同的价格在序列中的相同的组结束
grp
。 - 每组的行数。
老实说,我认为@舍甫琴科的解决方案更优雅一丁点。 它需要三个窗口的功能,太多,但只能在两个查询的步骤去做。 在小样本的快速测试也稍快。 所以,从+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
和time_trans time
为ts_trans timestamp
。
这是非常简单,非常快,提取date
或time
从timestamp
与投:
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,看看是否值是相同的
从我可以通过你的结果expections收集,你需要分区在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太多,如果有可能是在餐桌上,这是我所期望的多个日期。