如果对以下内容很重要,将使用Netezza后端+ SPSS Modeler和/或高级查询工具进行查询。我无法访问CLI。我试图了解是否有必要使用游标和遍历已排序的表来处理以下内容:
想象一下有两列的表,第一列是非唯一ID,第二列是日期。任何给定的ID可能会在表中多次出现一个或多个日期。
我的目标是从此表中选择日期间隔不少于固定天数的行,例如90.例如:
| ID | DATE |
===================
X 2014-01-01
X 2014-02-01
X 2014-07-01
Y 2014-02-01
Y 2014-06-01
Y 2014-07-01
在上面的示例中,我想为X选择的行将是1月1日和7月1日(不包括2月1日,因为从1月1日起不到90天),Y的行将是2月1日和6月1日(不包括7月1日,因为它是在先前案件的90天内。
实际上,表格中可能有超过100M的行。没有游标可以做到这一点吗?最佳方法是什么?
提前感谢任何建议!
编辑:在此扩展测试表数据。 SQL Fiddle
在上面编辑的示例中,所需的输出将是
| ID | DATE |
===================
X 2014-01-01
X 2014-04-01
X 2014-10-01
Y 2014-01-15
Y 2014-04-15
Y 2014-10-15
Z 2014-01-01
Z 2014-04-01
Z 2014-10-01
答案 0 :(得分:0)
我找到了一个成功的SPSS / Netezza原生迭代解决方案。 SPSS支持可以提前读取或后退的@OFFSET(字段,整数)函数。我曾尝试使用此函数,但在尝试使用" field"时遇到了与递归相关的错误。等于相同的字段,函数的结果与负整数一起读取前一个结果。
今天在另一个项目中我发现@OFFSET()的文档很差,虽然我相信它从第一行到最后一行的顺序w /表示预读的正整数,但实际上是倒退。它实际上解决了最后一行到第一行和正整数偏移实际上意味着读取前一行。使用我的原始方法重试并校正整数偏移上的符号消除了递归错误并解决了问题。
实际的解决方案可以这样。为了清楚起见,这种描述过于冗长,实际上大多数这些项目可以压缩到同一步骤中,并且它忽略了ID具有相同日期的多个实例的可能性(这是不难处理的)在比较中使用额外的逻辑,但对我的需求来说并不是必需的)。
不像MsSQL中提供的CTE递归方法那么优雅,但可以完全在SPSS v15中构建,并在几分钟内在完整的表上执行。
答案 1 :(得分:-1)
如果您接受在SQL Server中有效的内容,则以下代码将起作用:
With CTE as (
select A.ID, A.DATA, MIN(B.DATA) DATA1
from Table1 A
inner join Table1 B
on A.ID = B.ID
and DATEADD(DAY, 90, A.DATA) <= B.DATA
GROUP BY A.ID, A.DATA
), REC AS (
SELECT ID, MIN(DATA) DATA
FROM Table1
GROUP BY ID
UNION ALL
SELECT A.ID, B.DATA1
FROM REC A
INNER JOIN CTE B
ON A.ID = B.ID
AND A.DATA = B.DATA
)
SELECT *
FROM REC
ORDER BY ID, DATA
CTE的用户递归。通过选择每个ID的最小日期,后面的递归始终是最大日期,大于90天。但这只适用于SQL Server。
<强>更新强>
当您在其他地方获得实施的想法时,有多种方法来实现它是很有趣的。在SQL Server中也可以在TSQL中实现这种方式:
DECLARE @TABLE1 TABLE (ID VARCHAR(1), DATA DATE, DATA1 DATE)
INSERT INTO @TABLE1
select A.ID, A.DATA, MIN(B.DATA) DATA1
from (
SELECT ID, MIN(DATA) DATA
FROM Table1
GROUP BY ID
) A
inner join Table1 B
on A.ID = B.ID
and DATEADD(DAY, 90, A.DATA) <= B.DATA
GROUP BY A.ID, A.DATA
DECLARE @AUX INT = 0
WHILE (SELECT COUNT(*) FROM @TABLE1) <> @AUX
BEGIN
SELECT @AUX = COUNT(*) FROM @TABLE1
INSERT INTO @TABLE1
select *
from (
select A.ID, A.DATA, MIN(B.DATA) DATA1
from @Table1 A
inner join Table1 B
on A.ID = B.ID
and DATEADD(DAY, 90, A.DATA1) <= B.DATA
GROUP BY A.ID, A.DATA
) A
where not exists (
SELECT 1
FROM @TABLE1
WHERE ID = A.ID
AND DATA = A.DATA
AND DATA1 = A.DATA1
)
END
SELECT ID, DATA
FROM @TABLE1
UNION
SELECT ID, DATA1
FROM @TABLE1
UNION
SELECT ID, MIN(DATA) DATA
FROM Table1
GROUP BY ID