引用在同一选择语句中使用子查询创建的列

时间:2016-05-10 14:09:08

标签: sql-server-2008

现在我正在将一个非常古老的Access 97程序转换为.NET。有些东西很好,其他的东西,没有那么多。现在我正在转换查询报告。

DECLARE @CLIENT as varchar(16) = 'ClientsName'
DECLARE @StartDate as date = '2016-02-01'
DECLARE @EndDate as date = '2016-02-29'

SELECT DISTINCT NewHirePostProcessed.LOCATION, 
(SELECT COUNT(*) FROM NewHireList WHERE NewHireList.CLIENT=@CLIENT AND NewHireList.DOHIRE > @StartDate AND NewHireList.DOHIRE < @EndDate AND NewHirePostProcessed.LOCATION = LOCATION ) AS NumberHired,
(SELECT COUNT(*) FROM NewHireList WHERE NewHireList.CLIENT=@CLIENT AND NewHireList.DOHIRE > @StartDate AND NewHireList.DOHIRE < @EndDate AND NewHirePostProcessed.LOCATION = LOCATION AND CONTROL IS NOT NULL AND Qualify <> 'U') AS NumberReferred,
(NumberReferred/NumberHired) AS PercentRefered
FROM (SELECT * FROM NewHireList WHERE NewHireList.CLIENT = @CLIENT AND NewHireList.DOHIRE > @StartDate AND NewHireList.DOHIRE < @EndDate) AS NewHirePostProcessed;

我在引用表格其他列的数学部分时遇到了问题。

(NumberReferred/NumberHired) AS PercentRefered

我收到列不存在的错误。

SQL Error (207) Invalid column name 'NumberQualified'
Invalid column name 'NumberReferred'

我认为这是Access的一个怪癖,它允许旧的工作。有没有一种简单的方法可以让我在每个数学部分重做子查询?

2 个答案:

答案 0 :(得分:2)

是的,有。它被称为common table expression(简称CTE) 我们的想法是定义一个查询,然后可以使用它返回的结果集作为下一个sql语句的基础 它基本上是一种使用派生表的不同方式。

;WITH cte AS
(
    SELECT DISTINCT NewHirePostProcessed.LOCATION, 
                    (   
                        SELECT COUNT(*) 
                        FROM NewHireList 
                        WHERE NewHireList.CLIENT=@CLIENT 
                        AND NewHireList.DOHIRE > @StartDate 
                        AND NewHireList.DOHIRE < @EndDate 
                        AND NewHirePostProcessed.LOCATION = LOCATION 
                    ) AS NumberHired,
                    (
                        SELECT COUNT(*) 
                        FROM NewHireList 
                        WHERE NewHireList.CLIENT=@CLIENT 
                        AND NewHireList.DOHIRE > @StartDate 
                        AND NewHireList.DOHIRE < @EndDate 
                        AND NewHirePostProcessed.LOCATION = LOCATION 
                        AND CONTROL IS NOT NULL 
                        AND Qualify <> 'U'
                    ) AS NumberReferred,

    FROM (
        SELECT * 
        FROM NewHireList 
        WHERE NewHireList.CLIENT = @CLIENT 
        AND NewHireList.DOHIRE > @StartDate 
        AND NewHireList.DOHIRE < @EndDate
    ) AS NewHirePostProcessed
)

SELECT  NumberHired, 
        NumberReferred, 
        (NumberReferred/NumberHired) AS PercentRefered
FROM cte

它相当于这种方式,但更容易理解:

SELECT  NumberHired, 
        NumberReferred, 
        (NumberReferred/NumberHired) AS PercentRefered
FROM (
    SELECT DISTINCT NewHirePostProcessed.LOCATION, 
                    (   
                        SELECT COUNT(*) 
                        FROM NewHireList 
                        WHERE NewHireList.CLIENT=@CLIENT 
                        AND NewHireList.DOHIRE > @StartDate 
                        AND NewHireList.DOHIRE < @EndDate 
                        AND NewHirePostProcessed.LOCATION = LOCATION 
                    ) AS NumberHired,
                    (
                        SELECT COUNT(*) 
                        FROM NewHireList 
                        WHERE NewHireList.CLIENT=@CLIENT 
                        AND NewHireList.DOHIRE > @StartDate 
                        AND NewHireList.DOHIRE < @EndDate 
                        AND NewHirePostProcessed.LOCATION = LOCATION 
                        AND CONTROL IS NOT NULL 
                        AND Qualify <> 'U'
                    ) AS NumberReferred,

    FROM (
        SELECT * 
        FROM NewHireList 
        WHERE NewHireList.CLIENT = @CLIENT 
        AND NewHireList.DOHIRE > @StartDate 
        AND NewHireList.DOHIRE < @EndDate
    ) AS NewHirePostProcessed
) derived

您甚至可以使用一系列公用表表达式,如下所示:

;WITH NewHirePostProcessed AS
(
    SELECT * 
    FROM NewHireList 
    WHERE NewHireList.CLIENT = @CLIENT 
    AND NewHireList.DOHIRE > @StartDate 
    AND NewHireList.DOHIRE < @EndDate
)
, cte As 
(
    SELECT DISTINCT NewHirePostProcessed.LOCATION, 
                    (   
                        SELECT COUNT(*) 
                        FROM NewHireList 
                        WHERE NewHireList.CLIENT=@CLIENT 
                        AND NewHireList.DOHIRE > @StartDate 
                        AND NewHireList.DOHIRE < @EndDate 
                        AND NewHirePostProcessed.LOCATION = LOCATION 
                    ) AS NumberHired,
                    (
                        SELECT COUNT(*) 
                        FROM NewHireList 
                        WHERE NewHireList.CLIENT=@CLIENT 
                        AND NewHireList.DOHIRE > @StartDate 
                        AND NewHireList.DOHIRE < @EndDate 
                        AND NewHirePostProcessed.LOCATION = LOCATION 
                        AND CONTROL IS NOT NULL 
                        AND Qualify <> 'U'
                    ) AS NumberReferred,

    FROM NewHirePostProcessed
)

SELECT  NumberHired, 
        NumberReferred, 
        (NumberReferred/NumberHired) AS PercentRefered
FROM cte

答案 1 :(得分:1)

@Zohar是正确的(+1)。仅仅因为基础查询很糟糕,这里有一个进一步的简化 - 尽管你需要检查结果并确保其准确性:

;WITH cteBase
 as (--  Generate summaries
     select
        LOCATION
       ,count(*)  AS  NumberHired
       ,sum(case
              when CONTROL is not null and Qualify <> 'U' then 1
              else 0
            end)  AS  NumberReferred
      from NewHireList
      where CLIENT = @CLIENT
       and DOHIRE > @StartDate
       and DOHIRE < @EndDate
      group by LOCATION
    )
 select
   LOCATION
  ,NumberHired
  ,NumberReferred
  ,NumberReferred / NumberHired  AS  PercentRefered
 from cteBase