为表中的每个值运行SQL函数

时间:2015-02-17 20:43:45

标签: sql sql-server missing-data

这可能是一个新手问题,但我不能为我的生活弄清楚这一点。

在我解释我的存储过程之前,我将描述我的表并显示示例。有TicketBook表包含已发给单位的所有TicketBooks。票票是25张票。

例如:

                        TicketBooks
                        -----------
TicketBookNum  |  TicketNum  |  UnitID  |  FirstTicket  |  LastTicket | Used
 ---------------------------------------------------------------------------
     101              101          120           101           126       Yes
     101              102          120           101           126       Yes
     101              103          120           101           126       No
     101              104          120           101           126       Yes
     etc...

此表包含数据库中使用和未使用的所有故障单。

可以同时向不同的单位发放不同的TicketBook。因此,TicketBook 101可以发给120单元,而TicketBook 151可以发行到140.

我的存储过程需要做的是返回所有标记为未使用的故障单,但是还有一个大于标记为已使用的故障单。

示例:

TicketBookNum  |  TicketNum | Used
----------------------------------
   101              101        Yes
   101              102        Yes
   101              103        No
   101              104        Yes
   101              105        Yes
   101              106        No
   101              107        No
   etc..

因此存储过程返回Ticket 103,但不返回106107,因为在它们之后没有标记为Used的票证。

这是我正在使用的存储过程:

select TicketNum
from TicketBooks
where Used='No'
and TicketNum between 92226 and 92251
and TicketNum < (select top 1 TicketNum
                from TicketBooks
                where Used='Yes'
                and TicketNum between 92226 and 92251
                order by TicketNum desc)
order by TicketNum desc

这将从TicketBook 82226返回丢失的票据。如果我尝试更改between子句上的参数,则它不会返回正确的结果。任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:2)

您可以使用公用表表达式来包装范围限制并执行存在查询,如下所示:

;with cte as (
    select * from TicketBooks where TicketNum between 101 and 126
    )

select * from cte where Used = 'no'
and exists (
    select 1 
    from cte t
    where t.TicketNum > cte.ticketnum
    and t.used='yes'
    )

这仍然局限于硬编码范围;更好的选择可能是从源表中的FirstTicket / LastTicket值构建范围。

答案 1 :(得分:1)

试试这个

 ;WITH cte AS
(
 select TicketNum,ROW_NUMBER() OVER
    (PARTITION BY TicketBookNum,Used ORDER BY TicketNum) rn
from TicketBooks

)
SELECT * FROM cte 
where Used='No' AND rn =1 

实施例

CREATE TABLE #t (ticket INT ,ticketno INT, fla VARCHAR(10))

INSERT INTO #t VALUES(1,1,'yes'),
(1,2,'yes'),
(1,4,'No'),
(1,5,'No')

;WITH cte AS
(

SELECT *,ROW_NUMBER() OVER(PARTITION BY ticket,fla ORDER BY ticketno) rn FROM #t 
 )

 SELECT * FROM cte WHERE fla ='no'AND rn =1 

答案 2 :(得分:1)

select TicketNum
from TicketBooks as t
where Used='No'
    and TicketNum between 92226 and 92251
    and exists (
        select 1
        from TicketBooks as t2
        where t2.Used='Yes'
            /* not sure if you actually want to restrict the range here */
            and t2.TicketNum between 92226 and 92251
            and t2.TicketNum > t.TicketNum
    )
order by TicketNum desc

我无法理解您是想在票务簿或明确范围内搜索还是搜索什么。但我写这篇文章是为了向您展示EXISTS选项。您也可能会发现< ANY (...)< ALL (...)在将来有用。许多人忽略了这些。

答案 3 :(得分:1)

我相信我明白你要做什么。我认为您缺少的是您的子查询不会从外部查询映射到故障单。所以你想要这样的东西:

select TicketNum
from TicketBooks a
where Used='No'
and TicketNum < (select MAX(b.TicketNum)
            from TicketBooks b
            where b.Used='Yes'
            and b.TicketBookNum = a.TicketBookNum)
order by TicketNum desc