棘手的数据输入验证SQL查询

时间:2015-03-05 22:33:51

标签: sql sql-server-2008 while-loop cursor logic

我正在尝试开发一个验证用户数据输入的查询,但我陷入困境。基本上,我们正在处理有关每日24小时复合水样的信息。用户将输入复合结束的“COLDATE”并以DATETIME格式存储,如“2015-03-02 04:00:00.000”。然后他们将进入“Compstartdate”,这是varchar(8),看起来像“03/02/15”。最后,他们将进入“Compstarttime”,即varchar(5),看起来像“04:01”。

不要责怪我,我没有这样设置,让我们假设修复数据类型不是一种选择。

我正在处理的规则是,一天的“Compstart(日期/时间)”需要与前一天的“COLDATE”相匹配。到目前为止,我只能弄清楚如何查看“COLDATE(day) - 1 day”是否等于“Compstartdate(day)”。换句话说,我可以轻松地在一条记录中进行逻辑比较,但我不知道如何比较两条记录。

另外,我们只讨论2000条记录,因此性能考虑因素并不重要,我使用案例陈述证明了这一点。通过这个我的意思是一个涉及光标或while循环的解决方案对我来说是完全可以接受的。

这是我到目前为止所拥有的:

SELECT S.[SAMPNO]
      ,S.[LOCCODE]
      ,S.[COLDATE]
      ,U.[Compstartdate]
      ,U.[Compstarttime]

  FROM [dbo].[SAMPLE] as S
  JOIN [dbo].[SUSERFLDS] as U
  on S.SAMPNO = U.SAMPNO

  Where 
    Case
        When DATEPART(DAY, Convert(VARCHAR(10),U.Compstartdate,101)) != 
             DATEPART(DAY, DATEADD(DAY, -1, S.COLDATE))

        Then 'Yes' 

        ELSE 'NO'

    END ='YES' 

编辑:让我试着更好地解释问题。如果我今天收集24小时复合样本并将样本信息输入数据库,我将输入我收集样本的日期/时间(复合结束)和复合开始的日期/时间。因为它是24小时复合,今天样本的开始日期/时间应该等于昨天样本的结束时间(COLDATE)。因此,我需要采用相同的LOCCODE两个样品,但相隔一天使用COLDATE。然后查看前一个样本的COLDATE是否等于后一个样本的Compstartdate / time。

编辑#2:这是一些示例数据。

create table [SAMPLE] (
  SAMPNO   int,
  LOCCODE  char(7),
  COLDATE  datetime
);

create table SUSERFLDS (
 SAMPNO        int,
 Compstartdate char(8),
 Compstarttime char(5)
);

SET DATEFORMAT mdy;


insert into [SAMPLE] values (11,'Sample1','2015-03-02 04:00:00.000');
insert into [SAMPLE] values (12,'Sample1','2015-03-03 04:00:00.000');
insert into [SAMPLE] values (13,'Sample1','2015-03-04 04:00:00.000');
insert into [SAMPLE] values (14,'Sample1','2015-03-05 04:00:00.000');

insert into SUSERFLDS values (11, '03/01/15', '04:00');
insert into SUSERFLDS values (12, '03/02/15', '04:00');
insert into SUSERFLDS values (13, '03/03/15', '05:00');
insert into SUSERFLDS values (14, '03/04/15', '04:00');
--Compstartdate/time for SAMPNO 12
--does match COLDATE for SAMPNO 11
--Compstartdate/time for SAMPNO 13 
--should match COLDATE for SAMPNO 12

3 个答案:

答案 0 :(得分:1)

我认为你很困惑 - 没有必要循环使用 - 这实际上是联接的作用。

可悲的是,SQLFiddle目前似乎遇到了困难。这就是我要设置的例子:

create table SAMPLE (
  SAMPNO   int,
  LOCCODE  char(1),
  LOCDESCR char(1),
  LOGBATCH char(1),
  LOGUSER  char(1),
  COLDATE  datetime
);

create table SUSERFLDS (
 SAMPNO        int,
 Compstartdate char(8),
 Compstarttime char(5)
);

SET DATEFORMAT mdy;

insert into SAMPLE values (1, 'x','x','x','x','2015-03-01 04:00:00.000');
insert into SAMPLE values (2, 'x','x','x','x','2015-03-02 04:00:00.000');
insert into SAMPLE values (3, 'x','x','x','x','2015-03-03 04:00:00.000');
insert into SAMPLE values (4, 'x','x','x','x','2015-03-04 04:00:00.000');
insert into SAMPLE values (5, 'x','x','x','x','2015-03-05 04:00:00.000');

insert into SUSERFLDS values (2, '03/02/15', '04:00');
insert into SUSERFLDS values (3, '03/04/15', '04:00');
insert into SUSERFLDS values (4, '03/05/15', '04:00');
insert into SUSERFLDS values (5, '03/06/15', '05:00');

set dateformat mdy;

with example as (
select CAST( compstartdate +' '+ compstarttime as datetime) as compdatetime
from superflds)
select *
from sample
where  1 = (
  select count(*)
  from example
  where DATEPART(dy, compdatetime) = DATEPART(dy, coldate) + 1
  and   DATEPART(hh, compdatetime) = DATEPART(hh, coldate) 
  and   DATEPART(mi, compdatetime) = DATEPART(mi, coldate) 
  )

请在评论中提出任何问题或添加说明。

答案 1 :(得分:0)

终于明白了。这是一个查询,它提供了我正在寻找的东西:

set dateformat mdy;
With CTE1 as 
(
Select  S1.SAMPNO as SAMPNO1
        ,S1.COLDATE as COLDATE1
        ,S1.LOCCODE as LOCCODE1
        ,CAST( U1.Compstartdate +' '+ U1.Compstarttime as datetime) as Compstart1
From [SAMPLE] as S1 join
    [SUSERFLDS] as U1 on S1.SAMPNO = U1.SAMPNO
),
CTE2 as 
(
Select  S2.SAMPNO as SAMPNO2
        ,S2.COLDATE as COLDATE2
        ,S2.LOCCODE as LOCCODE2
        ,CAST( U2.Compstartdate +' '+ U2.Compstarttime as datetime) as Compstart2
From [SAMPLE] as S2 join
    [SUSERFLDS] as U2 on S2.SAMPNO = U2.SAMPNO
)
SELECT LOCCODE1
      ,SAMPNO1
      ,SAMPNO2
      ,COLDATE1
      ,COLDATE2
      ,Compstart1
From CTE1 join
        CTE2 on LOCCODE1 = LOCCODE2 and 
            COLDATE2 = DATEADD(Day, -1, COLDATE1)
Where Compstart1 != COLDATE2

如果您发现任何致命缺陷,请告诉我。

答案 2 :(得分:-1)

你只说"前一天的日期和时间"必须匹配。但是你匹配SAMPNO值。我猜测SUSERFLDS会进入第二天的样本时间。

您的查询启动正常,但您的参考表似乎是SUSERFLDS,因此应该是列出的第一个表。然后,您希望匹配具有相同样本编号和相同日期和时间的SAMPLE记录。

要进行比较,您可以将SAMPNO日期时间转换为与日期字符串格式相同的字符串(mm / dd / yy),并提取日期部分和时间部分以与SUSERFLDS中的字符串进行比较,或者将日期和时间字符串转换为日期时间值,然后只与SAMPNO日期时间进行比较。

使用后一个选项,这是查询:

select  U.[SAMPNO],
        U.[Compstartdate],
        U.[Compstarttime],
        S.[LOCCODE],
        S.[LOCDESCR],
        S.[LOGBATCH],
        S.[LOGUSER],
        S.[COLDATE]
from    SUSERFLDS u
left join SAMPLE  s
    on  s.SampNo  = u.SampNo
    and s.ColDate = Cast( u.CompStartdDate + ' ' + u.CompStartTime as datetime );

注意我使用外连接。这样你仍然可以看到所有的SUSERFLDS条目,但是使用NULL,其中样本数据应该是那些具有不匹配日期时间的样本。这使您可以立即指示日期和时间不匹配的位置。你可以添加

where  s.SampNo is null

您将只获得 样本日期时间不匹配的SUSERFLDS条目。在这种情况下,您可以省略选择列表中的所有S.XXX字段,因为它们始终只显示NULL。

然而,这并没有真正告诉你太多。如果您能看到实际的样本日期但只看到那些不匹配的日期会不会更好?

在这种情况下,请放弃"左"执行内部联接并将联接条件更改为"不等于"。像这样:

select  U.[SAMPNO],
        U.[Compstartdate],
        U.[Compstarttime],
        S.[LOCCODE],
        S.[LOCDESCR],
        S.[LOGBATCH],
        S.[LOGUSER],
        S.[COLDATE]
from    SUSERFLDS u
join    SAMPLE    s
    on  s.SampNo  = u.SampNo
    and s.ColDate <> Cast( u.CompStartdDate + ' ' + u.CompStartTime as datetime );

现在您可以看到SUSERFLDS日期和时间值以及SAMPLE日期时间值,但仅适用于那些不匹配的条目。这可以让你看出问题所在。