参数化查询返回错误的数据类型

时间:2017-10-12 14:07:34

标签: sql-server

请耐心等待我,我是SQL的初学者,现在我已经陷入困境几个小时了。我的每一个小问题都经常在论坛上得到解答,所以我没有任何理由在之前发帖。

我目前正在为统计信息统计信息中心编写查询,并在这个问题上遇到问题:

OmbudID和Grupp是整数 Födelsedatum和Startdatum是日期

在不使用UNION的情况下,查询工作正常,当从TimePicker给出值时,参数@start和@slut的工作方式与预期一致,但是一旦我使用UNION,查询似乎将具有预期值的参数转换为是varchar(3)。我尝试过CAST Startdatum AS Date,但这只给了我预期值varchar(1024)。

我尝试了多种不同的解决方案,但我转向你们。

提前谢谢!

SELECT '18-27' as Caption, count(*) as Count
FROM clients
WHERE DATEDIFF (year, clients.Födelsedatum, clients.Startdatum) < 28
AND ((clients.OmbudID = @ombud) OR (COALESCE (@ombud, '') = ''))
AND ((clients.Grupp = @grupp) OR (COALESCE (@grupp, '') = ''))
AND clients.Startdatum BETWEEN @start AND @slut
union all

SELECT '28-37' as Caption, count(*) as Count
FROM clients
WHERE DATEDIFF (year, clients.Födelsedatum, clients.Startdatum) >= 28
AND DATEDIFF (year, clients.Födelsedatum, clients.Startdatum) <= 37
AND ((clients.OmbudID = @ombud) OR (COALESCE (@ombud, '') = ''))
AND ((clients.Grupp = @grupp) OR (COALESCE (@grupp, '') = ''))
union all

SELECT '38-47' as Caption, count(*) as Count
FROM clients
WHERE DATEDIFF (year, clients.Födelsedatum, clients.Startdatum) >= 38
AND DATEDIFF (year, clients.Födelsedatum, clients.Startdatum) <= 47
AND ((clients.OmbudID = @ombud) OR (COALESCE (@ombud, '') = ''))
AND ((clients.Grupp = @grupp) OR (COALESCE (@grupp, '') = ''))
union all

SELECT '48-57' as Caption, count(*) as Count
FROM clients
WHERE DATEDIFF (year, clients.Födelsedatum, clients.Startdatum) >= 48
AND DATEDIFF (year, clients.Födelsedatum, clients.Startdatum) <= 57
AND ((clients.OmbudID = @ombud) OR (COALESCE (@ombud, '') = ''))
AND ((clients.Grupp = @grupp) OR (COALESCE (@grupp, '') = ''))
union all

SELECT '58-' as Caption, count(*) as Count
FROM clients
WHERE DATEDIFF (year, clients.Födelsedatum, clients.Startdatum) >= 58
AND ((clients.OmbudID = @ombud) OR (COALESCE (@ombud, '') = ''))
AND ((clients.Grupp = @grupp) OR (COALESCE (@grupp, '') = ''))

编辑:表格定义

CREATE TABLE [dbo].[clients] (
[KlientID]                           INT          IDENTITY (1, 1) NOT NULL,
[Förnamn]                            VARCHAR (25) NULL,
[Efternamn]                          VARCHAR (25) NULL,
[Födelsedatum]                       DATE         NULL,
[OmbudID]                            INT          NULL,
[Grupp]                              TINYINT      NULL,
[Startdatum]                         DATE         NULL,
[Slutdatum]                          DATE         NULL,
PRIMARY KEY CLUSTERED ([KlientID] ASC)

2 个答案:

答案 0 :(得分:0)

非常确定您可以将此查询简化为类似的内容。仍然不知道你面临的问题是什么。

declare 
    @sample nvarchar(max),
    @char nvarchar(1),
    @i_idx int,
    @temp int

    create table #RtnValue(
    Id int identity(1,1),
    A  nvarchar(max),
    [uni] int,
    [ascii] int 
    ) 

   -- set @sample to a single value from your dataset here
   select @sample = (select  top (1) [sample] from test.test)


While len(@sample) > 0
Begin
    Set @char = left(@sample,1)
        Insert Into #RtnValue (A, uni, [ascii])
        Select A = @char, UNI = UNICODE(@char), [ASCII] = ASCII(@char)  
    Set @sample = RIGHT(@sample,len(@sample)-1)
End

Select * from #RtnValue

答案 1 :(得分:0)

不确定参数类型是怎么回事,但我可以帮助解决这个问题。您可以做的一些事情会绕过需要多次从全表中获取UNION结果。

你可以这样做:

WITH Bands As (
    SELECT 18 "Low", 27 "High"
    Union 
    SELECT 28, 37
    Union
    SELECT 38, 47
    Union
    SELECT 48, 57
    Union
    SELECT 58, NULL
)
SELECT cast(b.Low as varchar(2)) + '-' + coalesce(cast(b.High as varchar(2)),'') "Caption",
       count(*) "Count"
FROM Bands b
INNER JOIN client c ON 
        DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= b.Low
    AND DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= coalesce(b.High, 9999)
WHERE   c.OmbudID = COALESCE(@ombud, c.OmbudID)
    AND c.Grupp   = COALESCE(@grupp, c.Grupp)
    AND c.Startdatum BETWEEN @start AND @slut
GROUP BY b.Low, b.High

我仍然包含一个UNION,但不在主表上。我喜欢这个选项,因为它允许你将它作为数据驱动。以后很容易改变你需要的乐队,你可以把它放在真正的桌子而不是CTE,如果你愿意,这意味着UNION根本不是必需的。

但这不是唯一的选择。你也可以试试这个:

 SELECT 
      CASE WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 27
              THEN '18-27'
          WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 28
           AND DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 37
              THEN '28-37'
           WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 28
           AND DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 47
              THEN '38-47'
          WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 48
           AND DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 57
              THEN '48-57'
          WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 58
              THEN '58-'  END "Caption",
          COUNT(*) "Count"
 FROM clients c
 WHERE   c.OmbudID = COALESCE(@ombud, c.OmbudID)
     AND c.Grupp   = COALESCE(@grupp, c.Grupp)
     AND c.Startdatum BETWEEN @start AND @slut
 GROUP BY
     CASE WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 27
              THEN '18-27'
          WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 28
           AND DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 37
              THEN '28-37'
           WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 28
           AND DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 47
              THEN '38-47'
          WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 48
           AND DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 57
              THEN '48-57'
          WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 58
              THEN '58-'  END    

但是代码重复在这里困扰着我。我们可以这样分解:

SELECT Caption, Count(*) "Count"
FROM (
     SELECT  CASE WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 27
                  THEN '18-27'
              WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 28
               AND DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 37
                  THEN '28-37'
               WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 28
               AND DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 47
                  THEN '38-47'
              WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 48
               AND DATEDIFF (year, c.Födelsedatum, c.Startdatum) <= 57
                  THEN '48-57'
              WHEN DATEDIFF (year, c.Födelsedatum, c.Startdatum) >= 58
                  THEN '58-'  END "Caption"
     FROM Clients c
     WHERE   c.OmbudID = COALESCE(@ombud, c.OmbudID)
         AND c.Grupp   = COALESCE(@grupp, c.Grupp)
         AND c.Startdatum BETWEEN @start AND @slut
) Ages
GROUP BY Caption

请注意,在SQL-land中,重复代码通常需要性能,即使从维护的角度来看,编写和危险似乎也很繁琐。

我这样说,因为有一个最后的选项会导致更多的代码:

SELECT Caption, Count(*) "Count"  
FROM 
(
    SELECT  CASE WHEN Age <= 27 THEN '18-27'
                 WHEN Age BETWEEN 28 AND 37 THEN '28-37'
                 WHEN Age BETWEEN 38 AND 47 THEN '38-47'
                 WHEN Age BETWEEN 48 AND 57 THEN '48-57'
                 ELSE '58-'  END "Caption"
    FROM (
         SELECT DATEDIFF (year, c.Födelsedatum, c.Startdatum) "Age"
         FROM Clients c
         WHERE   c.OmbudID = COALESCE(@ombud, c.OmbudID)
             AND c.Grupp   = COALESCE(@grupp, c.Grupp)
             AND c.Startdatum BETWEEN @start AND @slut
    ) Ages
) Bands
GROUP BY Caption

使用嵌套查询,您可以从里到外阅读。这首先考虑Age,然后在CASE语句中使用Age来获得Age频段,然后最后按Age band分组以获取标题和计数。它很有吸引力,因为您只需要一个DATEDIFF()CASE语句具有高可读性。嵌套查询可能会令人困惑,但可以通过CTE提高可读性和可维护性:

WITH ClientAges AS (
    SELECT DATEDIFF (year, c.Födelsedatum, c.Startdatum) "Age"
    FROM Clients c
    WHERE   c.OmbudID = COALESCE(@ombud, c.OmbudID)
        AND c.Grupp   = COALESCE(@grupp, c.Grupp)
        AND c.Startdatum BETWEEN @start AND @slut
), AgeBands As  (
    SELECT  CASE WHEN Age <= 27 THEN '18-27'
                 WHEN Age BETWEEN 28 AND 37 THEN '28-37'
                 WHEN Age BETWEEN 38 AND 47 THEN '38-47'
                 WHEN Age BETWEEN 48 AND 57 THEN '48-57'
                 ELSE '58-'  END "Caption"
    FROM ClientAges
)
SELECT Caption, COUNT(*) "Count"
FROM AgeBands
GROUP BY Caption

但是。如果Sql Server从这段代码中产生了一个不太理想的执行计划,我不会感到惊讶。它必须为每个记录生成一个文本字符串,而不是仅仅对记录进行分组并为每个组生成一次文本。您需要针对其他每个选项检查此选项,以了解它们的用途。

最后,看一下您的原始代码,我很好奇您是否希望Startdatum BETWEEN @start AND @slut条件仅适用于<=27频段或所有频段。我一直认为这是其他乐队的疏忽,但如果我错了,我可以做一个简单的调整,如果你对这个效果留下评论。