【问题标题】:TSQL Conditional Join Statement?TSQL 条件连接语句?
【发布时间】:2016-09-16 05:55:34
【问题描述】:

我正在处理一个动态查询,它允许我在数据库表中定义字段类型,然后提取在创建仪表板期间选择的用户定义字段列表以及为每个选择的值逻辑运算符。

例如,用户可以选择field1,即employeeID。然后他们可以提供他们想要搜索的 ID,它会将 fieldIDfieldValue 存储在一个表中,以便我们需要渲染数据时使用。

现在根据选择的字段,我可能需要连接另一个表以获取更多信息,例如员工姓名。

虽然这很简单,但当必须针对多个可能的表连接值时,棘手的部分就会发挥作用。如果我存储了一个employeeID,我会将该字段与员工表连接起来。但是,如果我存储了 storeID,则需要将该字段与 stores 表连接起来。

这是我在到达终点并意识到自己陷入困境之前的想法。基本上,我会说“如果这个字段是人员表isPeople=1,那么加入我们的employeeTable

如果此字段为isTool=1,请加入我们的工具表。

我基本上有一个fieldType 和一个fieldValue,根据类型,我需要根据我存储的值加入一个特定的表。

当我处理这个使其成为动态 sql 时,我意识到我不能使用 fl.* 字段来创建我的 IF 条件。

即。 IF (fl.isPeople =1) BEGIN ... JOIN Employee Table ... END

我认为采用动态方法是做到这一点的唯一方法,但现在我想不出解决问题的方法。

结论...

我正在尝试根据条件连接表和查询字段。由于我在正常的存储过程中似乎无法做到这一点,所以我尝试动态地做到这一点并最终出现在这里,我试图解释这个非常混乱的问题。

如果我可以进一步澄清,请告诉我。

更新:

USE [red]
GO
/****** Object:  StoredProcedure [dbo].[ti2_fetch_dashboard]    Script Date: 9/15/2016 9:55:39 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      Carl
-- Create date: Sept 13, 2016
-- Description: Fetch Single Dashboard for Editing
-- =============================================
ALTER PROCEDURE [dbo].[ti2_fetch_dashboard_test]
@dashboardID INT, @SQL NVARCHAR(MAX) = ''
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Fetch our dashboard
    SELECT @SQL = 'SELECT d.dashboardID,
           d.dashboardOwner,
           e.PreferredName AS ownerFirst,
           e.LastName AS ownerLast,
           e.NTID AS ownerNTID,
           d.dashboardTitle,
           d.dashboardDescription,
           d.dashboardType,
           d.creator,
           d.timestamp,
           d.lastUpdate,
           d.isDeleted,
           (SELECT sub.QID AS subscriberQID,
                   e.PreferredName AS subscriberFirst,
                   e.LastName AS subscriberLast,
                   e.NTID AS subscriberNTID
            FROM   dbo.ti_dashboard_subscribers AS sub
                   LEFT OUTER JOIN
                   dbo.EmployeeTable AS e
                   ON sub.QID = e.QID
            WHERE  sub.dashboardID = d.dashboardID
            FOR    XML PATH (''options''), ELEMENTS, TYPE, ROOT (''subscribers'')),
           (SELECT   f.fid,
                     f.fieldID,
                     f.[order],
                     cfg.primaryAllowed,
                     cfg.secondaryAllowed,
                     cfg.exportAllowed,
                     mf.fieldName,
                     mf.placeholder
            FROM     dbo.ti_dashboards_fields AS f
                     INNER JOIN
                     dbo.ti_dashboard_field_types AS ft
                     ON f.typeID = ft.fieldTypeID
                     INNER JOIN
                     dbo.ti_dashboard_master_fields_config AS cfg
                     ON f.fieldID = cfg.fieldID
                     INNER JOIN
                     dbo.ti_dashboards_master_fields AS mf
                     ON mf.fieldID = f.fieldID
            WHERE    f.dashboardID = d.dashboardID
                     AND ft.fieldTypeName = ''Primary''
            ORDER BY f.[order] ASC
            FOR      XML PATH (''fields''), ELEMENTS, TYPE, ROOT (''primaryFields'')),
           (SELECT   f.fid,
                     f.fieldID,
                     f.[order],
                     cfg.primaryAllowed,
                     cfg.secondaryAllowed,
                     cfg.exportAllowed,
                     mf.fieldName,
                     mf.placeholder
            FROM     dbo.ti_dashboards_fields AS f
                     INNER JOIN
                     dbo.ti_dashboard_field_types AS ft
                     ON f.typeID = ft.fieldTypeID
                     INNER JOIN
                     dbo.ti_dashboard_master_fields_config AS cfg
                     ON f.fieldID = cfg.fieldID
                     INNER JOIN
                     dbo.ti_dashboards_master_fields AS mf
                     ON mf.fieldID = f.fieldID
            WHERE    f.dashboardID = d.dashboardID
                     AND ft.fieldTypeName = ''Secondary''
            ORDER BY f.[order] ASC
            FOR      XML PATH (''fields''), ELEMENTS, TYPE, ROOT (''secondaryFields'')),
           (SELECT   f.fid,
                     f.fieldID,
                     f.[order],
                     cfg.primaryAllowed,
                     cfg.secondaryAllowed,
                     cfg.exportAllowed,
                     mf.fieldName,
                     mf.placeholder
            FROM     dbo.ti_dashboards_fields AS f
                     INNER JOIN
                     dbo.ti_dashboard_field_types AS ft
                     ON f.typeID = ft.fieldTypeID
                     INNER JOIN
                     dbo.ti_dashboard_master_fields_config AS cfg
                     ON f.fieldID = cfg.fieldID
                     INNER JOIN
                     dbo.ti_dashboards_master_fields AS mf
                     ON mf.fieldID = f.fieldID
            WHERE    f.dashboardID = d.dashboardID
                     AND ft.fieldTypeName = ''Export''
            ORDER BY f.[order] ASC
            FOR      XML PATH (''fields''), ELEMENTS, TYPE, ROOT (''exportFields'')),
            (SELECT   l.[fieldID],
                    -- Get the details of each of those fields
                     (SELECT fl.queryField,
                             fl.allowMultiple,
                             fl.isPeople,
                             fl.isDate,
                             fl.isSelect,
                             fl.isInput,
                             fl.isTool,
                             fl.selectOptions,
                             -- Get the values associcated with the fields
                             (SELECT dv.value';

                             -- If fl.isPeople = 1
                             SELECT @SQL += ', e.PreferredName AS FirstName, e.LastName, e.NTID, e.QID ';

                             -- If fl.isTool = 1
                             SELECT @SQL += ', t.toolName, t.toolType ';

                             -- Primary Table
                             SELECT @SQL += 'FROM dbo.ti_dashboards_logic AS dv ';

                             -- If fl.isPeople = 1
                             SELECT @SQL += 'LEFT OUTER JOIN dbo.EmployeeTable AS e ON dv.value = e.QID ';

                             -- If fl.isTool = 1
                             SELECT @SQL += 'LEFT OUTER JOIN ti_tools AS t ON dv.value = t.tool ';

                             -- Rest of Statement
                             SELECT @SQL += 'WHERE  dv.fieldID = l.fieldID
                                     AND dv.dashboardID = d.dashboardID
                              FOR    XML PATH (''data''), TYPE, ELEMENTS, ROOT (''values''))
                      FROM   dbo.ti_dashboard_master_fields_config AS fl
                      WHERE  fl.fieldID = l.fieldID
                             AND l.dashboardID = d.dashboardID
                      FOR    XML PATH (''fields''), TYPE, ELEMENTS, ROOT (''logicMeta''))
            FROM     [red].[dbo].[ti_dashboards_logic] AS l
            WHERE    l.dashboardID = d.dashboardID
            GROUP BY l.fieldID, l.dashboardID
            FOR      XML PATH (''fields''), TYPE, ELEMENTS, ROOT (''logicFields'')),
            (SELECT sdb.dashboardID ,
                       sdb.fieldID ,
                       sdb.sort ,
                       sdb.[order] ,
                       mf.fieldName
                FROM dbo.ti_dashboards_sorting AS sdb
                JOIN dbo.ti_dashboard_master_fields_config AS sf
                ON sdb.fieldID = sf.fieldID
                JOIN dbo.ti_dashboards_master_fields AS mf
                ON sf.fieldID = mf.fieldID
                WHERE sdb.dashboardID = d.dashboardID
                ORDER BY sdb.[order] ASC
                FOR    XML PATH (''fields''), TYPE, ELEMENTS, ROOT (''sortingFields'')
            )
    FROM   dbo.ti_dashboards AS d
           LEFT OUTER JOIN
           dbo.EmployeeTable AS e
           ON d.dashboardOwner = e.QID
    WHERE  d.dashboardID = @_dashboardID
           AND d.isDeleted = 0
    FOR    XML PATH (''data''), ELEMENTS, TYPE, ROOT (''root'')';

    EXEC sp_executesql @SQL, N'@_dashboardID INT', @_dashboardID = @dashboardID

END

【问题讨论】:

  • 发布您的代码(不是图片)
  • 我认为您实际上可能会从使用 ORM 工具中受益,因此您可以在代码层中进行更多动态查询,或者您可以使用多个查询并在几次访问数据库中提取数据,而不是试图一口气完成所有工作....如果您的数据集有点大,您很快就会遇到性能问题。
  • 您是否还可以向用户提供所有字段并将其留空(NULL)并在连接条件中检查?这样,您始终可以连接所有表,但仅限于使用的参数。

标签: sql sql-server tsql stored-procedures sql-server-2012


【解决方案1】:

您不能动态连接表,由数据和每行的不同列数驱动。

您只需要使用 UNION 来组合来自多个 SELECT 查询的结果。每个 SELECT 查询都有不同的连接和 WHERE 语句(isPeople、isTool 等)。

或者您可以加入所有相关表并在 ON 语句中添加更多条件,如下面的伪代码:

SELECT e.xxxx, t.yyyy, dv.zzzz, fl.ffff
FROM dbo.ti_dashboards_logic AS dv
   JOIN dbo.ti_dashboard_master_fields_config AS fl ON ....
   LEFT OUTER JOIN dbo.EmployeeTable  AS e ON dv.value = e.QID AND fl.isPeople = 1
   LEFT OUTER JOIN ti_tools AS t ON dv.value = t.tool AND fl.isTool = 1

所以每一行都有相同数量的列,t.yyyy 和 e.xxxx 将是 NULL 或不 NULL,具体取决于 fl.isTool 和 fl.isPeople 值。

【讨论】:

  • 您能否提供一些伪代码来说明您的建议?
  • 更新了我的答案。代码实在是太大了,难以阅读。您需要使用临时表或表变量将其拆分为多个部分。
猜你喜欢
  • 1970-01-01
  • 2012-07-08
  • 2011-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多