【问题标题】:Tricky data entry validation SQL query棘手的数据输入验证 SQL 查询
【发布时间】:2015-05-07 11:42:25
【问题描述】:

我正在尝试开发一个查询来验证用户数据输入,但我被卡住了。基本上,我们正在处理有关每日 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

【问题讨论】:

  • “我可以很容易地在一条记录中进行逻辑比较,但我不知道如何比较两条记录。” 你的意思是你可以比较天但也需要比较时间?
  • 虽然我确实需要比较日期和时间元素,但这并不是我所说的“比较两条记录”的意思。我的意思是我不知道如何将一天的数据与前一天的数据进行比较,这将在连接表中显示为单独的记录/行。
  • 我假设它是 SQL Server。什么版本?
  • 是SQL server 2008。
  • 您知道CompstartdateCompstarttime 是否总是有效值(有效日期和有效时间)?如果您可以假设它们会正确转换,那就会有所不同。

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


【解决方案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) 
  )

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

【讨论】:

  • 对不起,我已经对此进行了测试,但它并没有给我想要的东西。我需要将今天的示例开始日期/时间与昨天的结束日期/时间进行比较,并找到由于数据输入错误而导致它们不相等的实例。从逻辑上讲,今天的样本(24 小时综合)在昨天的样本结束时开始。此外,对于今天和昨天的样本,LOCCODE 和 LOCDESC 将是唯一相同的字段。
【解决方案2】:

您只是说“前一天”的日期和时间必须匹配。但是然后您匹配 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 日期时间值,但仅限于那些不匹配的条目。这可以让您了解问题所在。

【讨论】:

  • 我喜欢你的回答,很透彻,但我担心你可能误解了我的问题。我正在尝试查找一天的“Compstart(日期/时间)”与前一天的“COLDATE”不匹配的实例。 “Compstart(date/time)”在 SUSERFLDS 表中,“COLDATE”是 SAMPLE 表。这两个表由“SAMPNO”关联。
  • 让我们看看我是否可以进一步简化问题。每天都有一个新样本,它会获得一个独特的 SAMPNO。每个样品都有一个 COLDATE,它是 24 小时复合的结束。每个样本还具有开始 24 小时组合的日期和时间字段。从逻辑上讲,今天样本的开始需要与昨天样本的结束相同,对。所以我试图在开始和结束日期/时间不匹配的数据输入中找到错误。像泥一样清澈,对吧?
  • 您是说对于每个 Sample 条目,都有几个 SUSERFLDS 条目?并且您只是为了确保其中有一个与 Sample 条目具有相同的日期和时间?
  • 我在底部编辑了我的帖子。我添加了一些解释,希望能解决问题。
  • 为什么不创建一些示例数据?每个表只有几行,其中的数据与您要查找的内容相匹配,而另一行不匹配。
【解决方案3】:

终于明白了。这是给我我正在寻找的东西的查询:

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

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

【讨论】:

    猜你喜欢
    • 2016-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    相关资源
    最近更新 更多