如何确定给定项目的字段值是否仅增加?

时间:2013-10-29 20:12:28

标签: sql sql-server ms-access ms-access-2010

对于这个问题,我使用Access作为SQL Server的前端,并通过Excel VBA调用Access,尽管我可以使用直接的ADO连接,如果有一些T-SQL特定的函数在这里会更有用

我有一个表记录了一组项目的状态变化,例如:

+-------+-------+------------+
| docID | state |    date    |
+-------+-------+------------+
|   103 |     5 | 10/15/2013 |
|   103 |     6 | 10/18/2013 |
|   102 |     3 | 10/22/2013 |
|   103 |     2 | 11/1/2013  |
|   102 |     7 | 11/8/2013  |
+-------+-------+------------+

对于每个唯一的docID,我想弄清楚它的状态是否仅从第一个日期到最后一个日期增加,或者它是否会减少。在上述数据集中,103减少,102仅增加。我们可以假设条目将按日期顺序排列。

找到这个的一种方法是为每个docID创建一个对象,并将这些对象添加到字典中,将每个状态更改加载到一个列表中,并检查状态是否已减少,如下所示:

function isDecreasing(cl as changeList) as boolean

for c=2 to cl.count
 if cl.item(c).state < cl.item(c-1).state then
  isDecreasing=true
  exit function
 end if
next

isDecreasing=false

end function

但这会减慢我的查询速度,因为我必须将所有表数据转换为对象。这也意味着我将不得不编写大量额外的代码来创建和管理用于计算和生成报告的对象。

有没有办法在SQL Server或Access中编写可以对整个数据集执行相同类型分析的查询?

3 个答案:

答案 0 :(得分:2)

在他出色的回答中,戈登林诺夫说:

  

使用仅限访问功能时出现问题

真的?

对于给定的数据,我将其放在一个名为[StateChanges]的表中:

docID  state  date      
-----  -----  ----------
  103      5  2013-10-15
  103      6  2013-10-18
  102      3  2013-10-22
  103      2  2013-11-01
  102      7  2013-11-08

我可以在名为[PreviousDates]

的Access中创建以下保存的查询
SELECT t1.docID, t1.date, MAX(t2.date) AS PreviousDate
FROM
    StateChanges t1
    INNER JOIN
    StateChanges t2
        ON t2.docID = t1.docID
            AND t2.date < t1.date
GROUP BY t1.docID, t1.date

返回

docID  date        PreviousDate
-----  ----------  ------------
  102  2013-11-08  2013-10-22  
  103  2013-10-18  2013-10-15  
  103  2013-11-01  2013-10-18  

然后我可以使用以下查询来识别[state]发生故障的[docID]

SELECT curr.docID
FROM
    (
        PreviousDates pd
        INNER JOIN
        StateChanges curr
            ON curr.date = pd.date
    )
    INNER JOIN
    StateChanges prev
        ON prev.date = pd.PreviousDate
WHERE curr.state < prev.state

返回

docID
-----
  103

事实上,这两个查询都非常简单,我们可以将它们组合成一个查询,一次完成整个过程:

SELECT curr.docID
FROM
    (
        (
            SELECT t1.docID, t1.date, MAX(t2.date) AS PreviousDate
            FROM
                StateChanges t1
                INNER JOIN
                StateChanges t2
                    ON t2.docID = t1.docID
                        AND t2.date < t1.date
            GROUP BY t1.docID, t1.date
        ) PreviousDates
        INNER JOIN
        StateChanges curr
            ON curr.date = PreviousDates.date
    )
    INNER JOIN
    StateChanges prev
        ON prev.date = PreviousDates.PreviousDate
WHERE curr.state < prev.state

那么问题出在哪里?

答案 1 :(得分:1)

使用仅限访问功能时遇到问题。但是,如果您有SQL Server 2012,则可以使用lead() / lag()功能。还有另一种方法,就是使用row_number(),这是自SQL Server 2005以来可用的。

这是个主意。首先按docIdstate枚举每个date内的行。如果枚举相同,则序列不减少(基本上增加)。如果不同,那么道路上就会出现颠簸。这是代码:

select docid,
       (case when sum(case when rn_ds <> rn_sd then 1 else 0 end) = 0 then 'Increasing'
             else 'Decreasing'
        end) as SequenceType
from (select d.*,
             row_number() over (partition by docId order by date, state) as rn_ds,
             row_number() over (partition by docId order by state, date) as rn_sd
      from d
     ) d
group by docid;

请注意,我使用这两个字段使得排序更加复杂。这处理了一行中两个日期具有相同状态的情况(可能不允许,但也可能使技术更稳定)。

答案 2 :(得分:0)

问题:

  

对于每个唯一的docID,我想弄清楚它的状态是否只是从第一个日期到最后一个日期增加,或者它是否会减少。

所以你想要知道的是,对于给定的记录a,exist有一个记录ba的日期早于b的状态select docID from T a where exists ( select 1 from T b where b.date > a.date and b.state < a.state ) 低了。

所以请问。

{{1}}