在select语句中使用分区的语法错误

时间:2013-08-04 12:04:19

标签: sql-server

我使用以下查询来获取某些范围之间的年龄。我收到错误

Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'Age'.

以下是我的查询

SELECT DISTINCTROW Partition([Age],0,100,5) AS Age_Range, 
    Count(Patient_Ref_master.Age) AS Range_Count
    FROM Patient_Ref_master

    GROUP BY Partition([Age],0,100,5);

请指出我出错的地方。

2 个答案:

答案 0 :(得分:0)

DISTINCTROW PARTITION似乎是与Access相关的语法,在SQL Server中不存在,因此您收到语法错误就不足为奇了。

也许作为替代方案,你可以使用类似的东西:

with ranges as
(
  select lowAge = 0
    , highAge = 5
  union all
  select lowAge = lowAge + 5
    , highAge = highAge + 5
  from ranges
  where highAge < 100
)
select r.lowAge
  , r.highAge
  , patients = count(1)
from ranges r
  inner join Patient_Ref_master p on r.lowAge <= p.Age and r.highAge > p.Age
group by r.lowAge
  , r.highAge

SQL Fiddle with demo

这里我使用递归CTE来计算年龄范围,然后将此CTE加回到Patient_Ref_master表以获得现有范围内的计数。

因此,您无法在SQL Server中使用现有查询,但希望上面的查询将是一个有用的替代方案。

答案 1 :(得分:0)

根据link Partition使用四个参数,所有都是整数。基于这些信息,我在内联UDF中定义了:

CREATE FUNCTION dbo.AccessPartition
(
    @Value INT, -- Any whole number (+ or -)
    @Start INT, -- Should be >= 0
    @Stop INT, -- Should be > @Start
    @Interval INT -- Should be > 0
)
RETURNS TABLE
AS
RETURN
SELECT  z.RangeDescription, 
        CASE 
            WHEN @Value < x.Start THEN x.Start - 1
            WHEN @Value BETWEEN x.Start AND x.[Stop] THEN (@Value-x.Start)/x.Interval
            WHEN @Value > x.[Stop] THEN (x.[Stop]+1-x.Start)/x.Interval
        END AS RangeID
FROM
(
    SELECT 
        CASE WHEN @Start >= 0 THEN @Start ELSE 1/0 END AS Start, -- 1/0 = Internal error: @Start should be >= 0
        CASE WHEN @Start < @Stop THEN @Stop ELSE 1/0 END AS [Stop], -- 1/0 = Internal error: @Start should be less than @Stop
        CASE WHEN @Interval > 0 THEN @Interval ELSE 1/0 END AS Interval, -- 1/0 = Internal error: @Interval should be between @Start and @Stop  
        CASE 
            WHEN LEN(CONVERT(VARCHAR(11),@Start)) <= LEN(CONVERT(VARCHAR(11),@Stop)) THEN LEN(CONVERT(VARCHAR(11),@Stop)) 
            ELSE LEN(CONVERT(VARCHAR(11),@Start))
        END Width
)x
CROSS APPLY(
    SELECT 
        x.Start + ((@Value-x.Start)/x.Interval)*x.Interval AS RangeStart
        ,x.Start + ((@Value-x.Start)/x.Interval + 1)*x.Interval - 1 RangeStop
        ,REPLICATE(' ',x.Width) AS Padding
)y
CROSS APPLY(
    SELECT  
        CASE 
            WHEN @Value < x.Start THEN 
                LEFT(y.Padding,x.Width) 
                + ':' 
                + RIGHT(y.Padding+CONVERT(VARCHAR(11),x.Start-1),x.Width)
            WHEN @Value BETWEEN x.Start AND x.[Stop] THEN 
                RIGHT(y.Padding+CONVERT(VARCHAR(11),y.RangeStart),x.Width) 
                + ':' 
                + RIGHT(y.Padding+CONVERT(VARCHAR(11),y.RangeStop),x.Width) 
            WHEN @Value > x.[Stop] THEN 
                CONVERT(VARCHAR(11),x.[Stop])
                + ':' 
                + LEFT(y.Padding,x.Width) 
        END RangeDescription    
)z;
GO

您可以看到此函数首先检查参数,然后生成@Value参数的范围。然后它生成范围开始和停止。最后,它返回两个值(列):RangeDescriptionRangeIDRangeID可用于对行ASC / DESC进行排序。

用法:

CREATE TABLE dbo.Patient_Ref_master(
    ID INT IDENTITY(1,1) PRIMARY KEY,
    Age SMALLINT NOT NULL  -- I use SMALLINT only to test neg. values
);
GO
INSERT dbo.Patient_Ref_master(Age) VALUES (-2);
INSERT dbo.Patient_Ref_master(Age) VALUES (3);
INSERT dbo.Patient_Ref_master(Age) VALUES (4);
INSERT dbo.Patient_Ref_master(Age) VALUES (5);
INSERT dbo.Patient_Ref_master(Age) VALUES (6);
INSERT dbo.Patient_Ref_master(Age) VALUES (7);
INSERT dbo.Patient_Ref_master(Age) VALUES (8);
INSERT dbo.Patient_Ref_master(Age) VALUES (9);

INSERT dbo.Patient_Ref_master(Age) VALUES (12);
INSERT dbo.Patient_Ref_master(Age) VALUES (13);
INSERT dbo.Patient_Ref_master(Age) VALUES (14);
INSERT dbo.Patient_Ref_master(Age) VALUES (15);

INSERT dbo.Patient_Ref_master(Age) VALUES (19);
INSERT dbo.Patient_Ref_master(Age) VALUES (25);
INSERT dbo.Patient_Ref_master(Age) VALUES (50);
INSERT dbo.Patient_Ref_master(Age) VALUES (75);
INSERT dbo.Patient_Ref_master(Age) VALUES (102);
GO

SELECT a.*, '[' + f.RangeDescription + ']' AS Rng, f.RangeID
FROM Patient_Ref_master a
CROSS APPLY dbo.AccessPartition(a.Age,0,100,5) f
ORDER BY a.Age;

结果:

ID Age    Rng       RangeID
-- ------ --------- -------
1  -2     [   : -1] -1
2  3      [  0:  4] 0
3  4      [  0:  4] 0
4  5      [  5:  9] 1
5  6      [  5:  9] 1
6  7      [  5:  9] 1
7  8      [  5:  9] 1
8  9      [  5:  9] 1
9  12     [ 10: 14] 2
10 13     [ 10: 14] 2
11 14     [ 10: 14] 2
12 15     [ 15: 19] 3
13 19     [ 15: 19] 3
14 25     [ 25: 29] 5
15 50     [ 50: 54] 10
16 75     [ 75: 79] 15
17 102    [100:   ] 20

您的查询可能是:

SELECT f.RangeDescription, f.RangeID, COUNT(*) AS Cnt
FROM Patient_Ref_master a
CROSS APPLY dbo.AccessPartition(a.Age,0,100,5) f
GROUP BY f.RangeDescription, f.RangeID
ORDER BY f.RangeID;

在此示例中,我使用RangeID中的dbo.AccessPartion列对行进行排序。

结果:

RangeDescription RangeID Cnt
---------------- ------- ---
   : -1          -1      1
  0:  4          0       2
  5:  9          1       5
 10: 14          2       3
 15: 19          3       2
 25: 29          5       1
 50: 54          10      1
 75: 79          15      1
100:             20      1