请耐心等待我,我是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)
答案 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
频段或所有频段。我一直认为这是其他乐队的疏忽,但如果我错了,我可以做一个简单的调整,如果你对这个效果留下评论。