我有一个数据分析问题,我可以通过一些T-SQL或一些脚本轻松解决,但我想知道是否有一个聪明的SQL解决方案。问题是它稍微混淆了SQL的行独立性假设。
我有一个表,其中包含与用户关联的名称 - 值对,并按提交顺序排列,例如:
ID USERID VARIABLE VALUE SUBMITTED 3115 2287 votech05 2 2009-02-02 15:34:00 3116 2287 comcol05 1 2009-02-02 15:34:00 3117 2287 fouryr05 1 2009-02-02 15:35:00 3118 2287 none05 2 2009-02-02 15:35:00 3119 2287 ocol1_05 2 2009-02-02 15:44:00 3120 2287 disnone 2 2009-02-02 15:45:00 3121 2287 dissense 2 2009-02-02 15:49:00 3122 2287 dismobil 3 2009-02-02 15:51:00 3123 2287 dislearn 3 2009-02-02 15:51:00 3124 2287 disment 3 2009-02-02 15:52:00 3125 2287 disother 2 2009-02-02 15:55:00 3126 2287 disrefus 7 2009-02-02 15:58:00
我希望能够确定最大的相同值组的值和计数(当数据被命令为ID主键时)。所以,对于上面的例子,因为我有4个值= 2按顺序出现,只有3个值= 3,我想报告:
USERID VALUE COUNT 2287 2 4
给定用户。
同样,这可以使用其他工具相当快速地完成,但由于数据集非常大(大约7500万条记录)并经常更改,因此能够通过查询解决此问题会很好。我正在使用SQL Server 2005。
答案 0 :(得分:3)
(评论后编辑)
您可以通过为每组连续值分配“头”编号来实现。之后,选择每行的头编号,并按人头聚合。
这是一个例子,CTE的可读性:
WITH
OrderedTable as (
select value, rownr = row_number() over (order by userid, id)
from YourTable
where userid = 2287
),
Heads as (
select cur.rownr, CurValue = cur.value
, headnr = row_number() over (order by cur.rownr)
from OrderedTable cur
left join OrderedTable prev on cur.rownr = prev.rownr+1
where IsNull(prev.value,-1) != cur.value
),
ValuesWithHead as (
select value
, HeadNr = (select max(headnr)
from Heads
where Heads.rownr <= data.rownr)
from OrderedTable data
)
select Value, [Count] = count(*)
from ValuesWithHead
group by HeadNr, value
order by count(*) desc
这将输出:
Value Count
2 4
3 3
1 2
2 1
2 1
7 1
使用“top 1”仅选择第一行。
这是我创建测试数据的查询:
create table YourTable (
id int primary key,
userid int,
variable varchar(25),
value int
)
insert into YourTable (id, userid, variable, value) values (3115, 2287, 'votech05', 2)
insert into YourTable (id, userid, variable, value) values (3116, 2287, 'comcol05', 1)
insert into YourTable (id, userid, variable, value) values (3117, 2287, 'fouryr05', 1)
insert into YourTable (id, userid, variable, value) values (3118, 2287, 'none05', 2)
insert into YourTable (id, userid, variable, value) values (3119, 2287, 'ocol1_05', 2)
insert into YourTable (id, userid, variable, value) values (3120, 2287, 'disnone', 2)
insert into YourTable (id, userid, variable, value) values (3121, 2287, 'dissense', 2)
insert into YourTable (id, userid, variable, value) values (3122, 2287, 'dismobil', 3)
insert into YourTable (id, userid, variable, value) values (3123, 2287, 'dislearn', 3)
insert into YourTable (id, userid, variable, value) values (3124, 2287, 'disment', 3)
insert into YourTable (id, userid, variable, value) values (3125, 2287, 'disother', 2)
insert into YourTable (id, userid, variable, value) values (3126, 2287, 'disrefus', 7)
答案 1 :(得分:2)
这可能是游标最好解决的问题之一。试一试。它应该是接近的,但它没有经过测试,因为你没有提供带有样本数据的CREATE TABLE和INSERT语句来使这很容易。
declare @userid int
set @userid = 2287;
declare C cursor fast_forward for
select VALUE from T
where USERID = @userid
order by ID;
declare @value int, @prevvalue int;
declare @runcount int, @runlongest int;
set @runlongest = 0;
declare @valuelongest int;
open C;
fetch next from C into @value;
while @@fetch_status = 0 begin
if @value = @prevvalue set @runcount = @runcount + 1 else set @runcount = 1;
if @runcount > @runlongest begin
set @runlongest = @runcount;
set @valuelongest = @value;
end;
set @prevvalue = @value;
fetch next from C into @value;
end;
select @userid as USERID, @valuelongest as VALUE, @runlongest as [COUNT];
close C;
deallocate C;
75M行不会很快,但也可能不会太慢。如果您的运行时间非常长,并且您拥有正确的索引,则可以通过在临时表中使用row_number对行进行编号,然后使用一次跳过运行的WHILE循环来做得更好。如果您认为值得关注,请告诉我(如果可以,请使用示例数据发布CREATE TABLE和INSERT语句)。
答案 2 :(得分:0)
没有测试它我认为以下应该有效:
Row_number()over(按用户ID划分,按id划分值)
完成此操作后,只需选择row_nunber最高的那个
请告诉我这是否有效!!
谢谢,Edi