3

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

我有一个记录一组项目状态更改的表,例如:

+-------+-------+------------+
| 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  |
+-------+-------+------------+

对于每个 unique 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 中编写可以对整个数据集执行相同类型分析的查询?

4

3 回答 3

2

Gordon Linoff 在他的出色回答中说:

您在使用仅限访问功能时遇到问题

真的吗?

对于给定的数据,我已将其放入名为 [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  

然后我可以使用以下查询来识别 [docID] 的 [state] 下降的位置

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

那么问题出在哪里?

于 2013-10-29T23:24:02.437 回答
1

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

这是想法。枚举每个docIdfirst bystate和 by中的行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;

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

于 2013-10-29T20:22:03.157 回答
0

问题:

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

所以你想知道的是,对于给定的记录a,是否存在exist日期b较早a但状态b较低的记录。

所以就这么问吧。

select docID 
from T a 
where 
exists (
    select 1 from T b where b.date > a.date and b.state < a.state
)
于 2013-10-29T23:31:51.147 回答