Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 对同一个表和一个;“在什么情况下”;在选择_Sql_Sql Server 2008 - Fatal编程技术网

Sql 对同一个表和一个;“在什么情况下”;在选择

Sql 对同一个表和一个;“在什么情况下”;在选择,sql,sql-server-2008,Sql,Sql Server 2008,在我的组织中,客户可以一次注册多个计划。我有一个表,其中列出了一个客户端作为唯一行注册的所有程序,以及他们在该程序中注册的日期 通过使用外部联接,我可以从表(比如客户端已完成的测试表)中获取任何客户端名称和日期,并让它返回客户端在该特定日期参与的所有程序。如果某个客户机在该日期在多个程序中,它会为该客户机在该日期所在的每个程序复制该表中的数据 我的问题是,我希望它只返回一个程序作为每个客户机和日期的“主程序”,即使他们在该日期在多个程序中。我已经创建了一个层次结构,应该选择该程序作为其主程序并返

在我的组织中,客户可以一次注册多个计划。我有一个表,其中列出了一个客户端作为唯一行注册的所有程序,以及他们在该程序中注册的日期

通过使用外部联接,我可以从表(比如客户端已完成的测试表)中获取任何客户端名称和日期,并让它返回客户端在该特定日期参与的所有程序。如果某个客户机在该日期在多个程序中,它会为该客户机在该日期所在的每个程序复制该表中的数据

我的问题是,我希望它只返回一个程序作为每个客户机和日期的“主程序”,即使他们在该日期在多个程序中。我已经创建了一个层次结构,应该选择该程序作为其主程序并返回

例如:

1.)住院病人

2.)门诊临床

3.)门诊职业

4.)门诊康乐中心

因此,如果客户在该日期同时登记在门诊临床、门诊职业、门诊娱乐,则只会将“门诊临床”作为计划返回

我这样做的想法是多次使用前面的程序加入表,如下所示:

FROM dbo.TestTable as TestTable

LEFT OUTER JOIN dbo.PreviousPrograms as PreviousPrograms1
ON TestTable.date = PreviousPrograms1.date AND PreviousPrograms1.type = 'Inpatient'

LEFT OUTER JOIN dbo.PreviousPrograms as PreviousPrograms2
ON TestTable.date = PreviousPrograms2.date AND PreviousPrograms2.type = 'Outpatient Clinical'

LEFT OUTER JOIN dbo.PreviousPrograms as PreviousPrograms3
ON TestTable.date = PreviousPrograms3.date AND PreviousPrograms3.type = 'Outpatient Vocational'

LEFT OUTER JOIN dbo.PreviousPrograms as PreviousPrograms4
ON TestTable.date = PreviousPrograms4.date AND PreviousPrograms4.type = 'Outpatient Recreational'
然后在SELECT语句中执行以下条件:

SELECT

CASE 
        WHEN PreviousPrograms1.name IS NOT NULL
            THEN PreviousPrograms1.name
        WHEN PreviousPrograms1.name IS NULL AND PreviousPrograms2.name IS NOT NULL
            THEN PreviousPrograms2.name
        WHEN PreviousPrograms1.name IS NULL AND PreviousPrograms2.name IS NULL AND PreviousPrograms3.name IS NOT NULL
            THEN PreviousPrograms3.name
        WHEN PreviousPrograms1.name IS NULL AND PreviousPrograms2.name IS NULL AND PreviousPrograms3.name IS NOT NULL AND PreviousPrograms4.name IS NOT NULL
            THEN PreviousPrograms4.name
        ELSE NULL
        END as PrimaryProgram
更大的问题是,在我的实际表中,它可能不仅仅是四个可能的程序,而且select语句和联接已经够麻烦了

有没有更有效的方法来选择零件或连接零件?或者可能是一个更好的方法来一起做


我正在使用SQL Server 2008。

您可以使用包含所有程序类型及其优先级的桥接表来简化联接(我的SQL Server语法有点生疏):

此表将包含所有程序类型,程序优先级将反映您在问题中指定的优先级

至于案件的部分,这将取决于所涉及的记录数量。我通常会做的一个技巧是这样的(假设programPriority是一个介于10和99之间的数字,并且任何类型都不能超过30个字节,因为我很懒):


您可以使用包含所有程序类型及其优先级的桥接表来简化联接(我的sql server语法有点生疏):

此表将包含所有程序类型,程序优先级将反映您在问题中指定的优先级

至于案件的部分,这将取决于所涉及的记录数量。我通常会做的一个技巧是这样的(假设programPriority是一个介于10和99之间的数字,并且任何类型都不能超过30个字节,因为我很懒):

您可以使用以下方法简化(替换)您的
案例

COALESCE()
返回第一个非空值

由于您的设计,您仍然需要使用
JOIN
s,但是如果您使用非常短的别名,例如
PP1
,而不是
以前的程序1
,则阅读起来会容易得多,这只是代码噪音要小得多。

您可以使用以下替代方法简化(替换)您的
案例

COALESCE()
返回第一个非空值


由于您的设计,您仍然需要
连接
,但是如果您使用非常短的别名,例如
PP1
,而不是
以前的程序1
,阅读起来会容易得多,这只是代码噪音要小得多。

您可以使用子查询来实现这一点,或者您可以重构它以使用CTE,请看以下内容,看看是否有意义:

DECLARE @testTable TABLE
(
    [id] INT IDENTITY(1, 1),
    [date] datetime
)
DECLARE @previousPrograms TABLE
(
    [id] INT IDENTITY(1,1),
    [date] datetime,
    [type] varchar(50)
)

INSERT INTO @testTable ([date])
SELECT '2013-08-08'
UNION ALL SELECT '2013-08-07'
UNION ALL SELECT '2013-08-06'

INSERT INTO @previousPrograms ([date], [type])
-- a sample user as an inpatient
SELECT '2013-08-08', 'Inpatient'
-- your use case of someone being enrolled in all 3 outpation programs
UNION ALL SELECT '2013-08-07', 'Outpatient Recreational'
UNION ALL SELECT '2013-08-07', 'Outpatient Clinical'
UNION ALL SELECT '2013-08-07', 'Outpatient Vocational'

-- showing our workings, this is what we'll join to
SELECT 
    PPP.[date],
    PPP.[type],
    ROW_NUMBER() OVER (PARTITION BY PPP.[date] ORDER BY PPP.[Priority]) AS [RowNumber]
FROM (
    SELECT
        [type],
        [date],
        CASE 
            WHEN [type] = 'Inpatient' THEN 1
            WHEN [type] = 'Outpatient Clinical' THEN 2
            WHEN [type] = 'Outpatient Vocational' THEN 3
            WHEN [type] = 'Outpatient Recreational' THEN 4
            ELSE 999
        END AS [Priority]
    FROM @previousPrograms
) PPP -- Previous Programs w/ Priority

SELECT
    T.[date],
    PPPO.[type]
FROM @testTable T
LEFT JOIN (
    SELECT 
        PPP.[date],
        PPP.[type],
        ROW_NUMBER() OVER (PARTITION BY PPP.[date] ORDER BY PPP.[Priority]) AS [RowNumber]
    FROM (
        SELECT
            [type],
            [date],
            CASE 
                WHEN [type] = 'Inpatient' THEN 1
                WHEN [type] = 'Outpatient Clinical' THEN 2
                WHEN [type] = 'Outpatient Vocational' THEN 3
                WHEN [type] = 'Outpatient Recreational' THEN 4
                ELSE 999
            END AS [Priority]
        FROM @previousPrograms
    ) PPP -- Previous Programs w/ Priority
) PPPO -- Previous Programs w/ Priority + Order
    ON T.[date] = PPPO.[date] AND PPPO.[RowNumber] = 1
基本上,我们有最深的子选择,根据类型给所有以前的程序一个优先级,然后包装子选择给它们每个日期的行号,所以我们只能选择行号为1的程序


我猜您可能需要包含UR号码或其他患者标识符,只需将其作为输出添加到sub selects并更改连接。

您可以使用sub查询来实现这一点,或者您可以将其重构为使用CTE,查看以下内容,看看是否有意义:

DECLARE @testTable TABLE
(
    [id] INT IDENTITY(1, 1),
    [date] datetime
)
DECLARE @previousPrograms TABLE
(
    [id] INT IDENTITY(1,1),
    [date] datetime,
    [type] varchar(50)
)

INSERT INTO @testTable ([date])
SELECT '2013-08-08'
UNION ALL SELECT '2013-08-07'
UNION ALL SELECT '2013-08-06'

INSERT INTO @previousPrograms ([date], [type])
-- a sample user as an inpatient
SELECT '2013-08-08', 'Inpatient'
-- your use case of someone being enrolled in all 3 outpation programs
UNION ALL SELECT '2013-08-07', 'Outpatient Recreational'
UNION ALL SELECT '2013-08-07', 'Outpatient Clinical'
UNION ALL SELECT '2013-08-07', 'Outpatient Vocational'

-- showing our workings, this is what we'll join to
SELECT 
    PPP.[date],
    PPP.[type],
    ROW_NUMBER() OVER (PARTITION BY PPP.[date] ORDER BY PPP.[Priority]) AS [RowNumber]
FROM (
    SELECT
        [type],
        [date],
        CASE 
            WHEN [type] = 'Inpatient' THEN 1
            WHEN [type] = 'Outpatient Clinical' THEN 2
            WHEN [type] = 'Outpatient Vocational' THEN 3
            WHEN [type] = 'Outpatient Recreational' THEN 4
            ELSE 999
        END AS [Priority]
    FROM @previousPrograms
) PPP -- Previous Programs w/ Priority

SELECT
    T.[date],
    PPPO.[type]
FROM @testTable T
LEFT JOIN (
    SELECT 
        PPP.[date],
        PPP.[type],
        ROW_NUMBER() OVER (PARTITION BY PPP.[date] ORDER BY PPP.[Priority]) AS [RowNumber]
    FROM (
        SELECT
            [type],
            [date],
            CASE 
                WHEN [type] = 'Inpatient' THEN 1
                WHEN [type] = 'Outpatient Clinical' THEN 2
                WHEN [type] = 'Outpatient Vocational' THEN 3
                WHEN [type] = 'Outpatient Recreational' THEN 4
                ELSE 999
            END AS [Priority]
        FROM @previousPrograms
    ) PPP -- Previous Programs w/ Priority
) PPPO -- Previous Programs w/ Priority + Order
    ON T.[date] = PPPO.[date] AND PPPO.[RowNumber] = 1
基本上,我们有最深的子选择,根据类型给所有以前的程序一个优先级,然后包装子选择给它们每个日期的行号,所以我们只能选择行号为1的程序


我猜您可能需要包含UR编号或其他患者标识符,只需将其作为输出添加到两个子选择并更改连接。

您是否将程序本身存储在不同的表中?如果是这样,我会添加一个代表优先级的列,并将其包含在查询中。按等级排序,然后选择top 1。您是否将程序本身存储在不同的表中?如果是这样,我会添加一个代表优先级的列,并将其包含在查询中。按排名排序,然后选择前1名。
SELECT
  COALESCE(PreviousPrograms1.name, PreviousPrograms2.name,
    PreviousPrograms3.name, PreviousPrograms4.name) AS PreviousProgram
DECLARE @testTable TABLE
(
    [id] INT IDENTITY(1, 1),
    [date] datetime
)
DECLARE @previousPrograms TABLE
(
    [id] INT IDENTITY(1,1),
    [date] datetime,
    [type] varchar(50)
)

INSERT INTO @testTable ([date])
SELECT '2013-08-08'
UNION ALL SELECT '2013-08-07'
UNION ALL SELECT '2013-08-06'

INSERT INTO @previousPrograms ([date], [type])
-- a sample user as an inpatient
SELECT '2013-08-08', 'Inpatient'
-- your use case of someone being enrolled in all 3 outpation programs
UNION ALL SELECT '2013-08-07', 'Outpatient Recreational'
UNION ALL SELECT '2013-08-07', 'Outpatient Clinical'
UNION ALL SELECT '2013-08-07', 'Outpatient Vocational'

-- showing our workings, this is what we'll join to
SELECT 
    PPP.[date],
    PPP.[type],
    ROW_NUMBER() OVER (PARTITION BY PPP.[date] ORDER BY PPP.[Priority]) AS [RowNumber]
FROM (
    SELECT
        [type],
        [date],
        CASE 
            WHEN [type] = 'Inpatient' THEN 1
            WHEN [type] = 'Outpatient Clinical' THEN 2
            WHEN [type] = 'Outpatient Vocational' THEN 3
            WHEN [type] = 'Outpatient Recreational' THEN 4
            ELSE 999
        END AS [Priority]
    FROM @previousPrograms
) PPP -- Previous Programs w/ Priority

SELECT
    T.[date],
    PPPO.[type]
FROM @testTable T
LEFT JOIN (
    SELECT 
        PPP.[date],
        PPP.[type],
        ROW_NUMBER() OVER (PARTITION BY PPP.[date] ORDER BY PPP.[Priority]) AS [RowNumber]
    FROM (
        SELECT
            [type],
            [date],
            CASE 
                WHEN [type] = 'Inpatient' THEN 1
                WHEN [type] = 'Outpatient Clinical' THEN 2
                WHEN [type] = 'Outpatient Vocational' THEN 3
                WHEN [type] = 'Outpatient Recreational' THEN 4
                ELSE 999
            END AS [Priority]
        FROM @previousPrograms
    ) PPP -- Previous Programs w/ Priority
) PPPO -- Previous Programs w/ Priority + Order
    ON T.[date] = PPPO.[date] AND PPPO.[RowNumber] = 1