Sql过程 - 根据另一个表中的状态选择数据

时间:2016-02-19 14:55:33

标签: sql sql-server join stored-procedures

我正在尝试为我正在开发的程序创建搜索功能。我现在的查询检查已选择的记录状态,可以是以下任何一种:

  • 支付&未付
  • 仅付费
  • 仅支付
  • 删除记录

然后执行一个select查询,它会提取与这些记录状态匹配的所有记录,这里是查询:

    PROCEDURE [dbo].[SearchSQL]
    -- Add the parameters for the stored procedure here
    @logging_ref as varchar(50) = NULL,
    @summit_ac_no as varchar(50) = NULL,
    @contract_no as varchar(50) = NULL,
    @invoice_no as varchar(50) = NULL,
    @company as varchar(50) = NULL,
    @paycert as varchar(50) = NULL,
    @record_type as integer = NULL,
    @qs as varchar(50) = NULL,
    @records as int = NULL,
    @state as int = NULL
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    IF @state = 1 
        Begin
            SELECT TOP(@records) 
            -- Reference Columns - Used to identify a Record --
                r.r_id AS 'ref',  
                grossVal AS 'gross', 
                payCert AS 'cert', 
            -- Data Columns for Display --
                logRef as 'Logging Reference', 
                db_recTypes.recordName AS 'Record Type', 
                invNo as 'Invoice No.', 
                invDate as 'Invoice Date', 
                accNo as 'Summit Account No.',
                db_accountNo.name as 'Company Name', 
                contract as 'Contract No.', 
                taxStatus as 'Tax Status', 
                netVal as 'Net Value', 
                vat as 'V.A.T', 
                grossVal as 'Gross Value',
                paycert as 'Payment Certificate No.', 
                period as 'Period', 
                paydate as 'Anticipated Payment Date', 
                db_qs.name as 'QS record sent to', 
                sentDate as 'Date sent to QS',
                db_sentMethod.name as 'Sent Via', 
                returnedDate as 'Date Returned', 
                r.deleted as 'Removed', 
                lastModified as 'Last Modified', 
                creationDate as 'Date Created', 
                db_users.name as 'Creation User',
                p.date as 'Date Paid'
            --  Main Table to Reference --
                FROM db_records as r
            -- Proceed with SQL JOINs -- 
                JOIN db_recTypes
                ON db_recTypes.recordID = r.recType
                Join db_accountNo
                ON db_accountNo.com_id = r.accNo
                Join db_qs
                On db_qs.q_id = r.sentTo
                JOIN db_sentMethod 
                On db_sentMethod.v_id = r.sentVia
                Join db_users
                On db_users.u_id = r.u_id
                FULL OUTER JOIN db_payments as p
                ON p.r_id = r.r_id
            -- Check For the following values
                WHERE 
                    (@logging_ref IS NULL OR logRef LIKE '%' + @logging_ref + '%')
                    AND (@summit_ac_no IS NULL OR accNo LIKE '%' + @summit_ac_no + '%') 
                    AND (@contract_no IS NULL OR contract LIKE '%' + @contract_no + '%')
                    AND (@invoice_no IS NULL OR invNo LIKE '%' + @invoice_no + '%') 
                    AND (@company IS NULL OR db_accountNo.name LIKE '%' + @company + '%')
                    AND (@paycert IS NULL OR payCert LIKE '%' + @paycert + '%') 
                    AND (@record_type IS NULL OR recType = @record_type) 
                    AND (@qs IS NULL OR db_qs.name LIKE '%' + @qs + '%')
                    AND r.deleted = 0
        END
    ELSE
        Begin
            IF @state = 2
                BEGIN
                    SELECT TOP(@records) 
                    -- Reference Columns - Used to identify a Record --
                        r.r_id AS 'ref',  
                        grossVal AS 'gross', 
                        payCert AS 'cert', 
                    -- Data Columns for Display --
                        logRef as 'Logging Reference', 
                        db_recTypes.recordName AS 'Record Type', 
                        invNo as 'Invoice No.', 
                        invDate as 'Invoice Date', 
                        accNo as 'Summit Account No.',
                        db_accountNo.name as 'Company Name', 
                        contract as 'Contract No.', 
                        taxStatus as 'Tax Status', 
                        netVal as 'Net Value', 
                        vat as 'V.A.T', 
                        grossVal as 'Gross Value',
                        paycert as 'Payment Certificate No.', 
                        period as 'Period', 
                        paydate as 'Anticipated Payment Date', 
                        db_qs.name as 'QS record sent to', 
                        sentDate as 'Date sent to QS',
                        db_sentMethod.name as 'Sent Via', 
                        returnedDate as 'Date Returned', 
                        r.deleted as 'Removed', 
                        lastModified as 'Last Modified', 
                        creationDate as 'Date Created', 
                        db_users.name as 'Creation User',
                        p.date as 'Date Paid'
                    --  Main Table to Reference --
                        FROM db_records as r
                    -- Proceed with SQL JOINs -- 
                        JOIN db_recTypes
                        ON db_recTypes.recordID = r.recType
                        Join db_accountNo
                        ON db_accountNo.com_id = r.accNo
                        Join db_qs
                        On db_qs.q_id = r.sentTo
                        JOIN db_sentMethod 
                        On db_sentMethod.v_id = r.sentVia
                        Join db_users
                        On db_users.u_id = r.u_id
                        FULL OUTER JOIN db_payments as p
                        ON p.r_id = r.r_id
                    -- Check For the following values
                        WHERE 
                            (@logging_ref IS NULL OR logRef LIKE '%' + @logging_ref + '%')
                            AND (@summit_ac_no IS NULL OR accNo LIKE '%' + @summit_ac_no + '%') 
                            AND (@contract_no IS NULL OR contract LIKE '%' + @contract_no + '%')
                            AND (@invoice_no IS NULL OR invNo LIKE '%' + @invoice_no + '%') 
                            AND (@company IS NULL OR db_accountNo.name LIKE '%' + @company + '%')
                            AND (@paycert IS NULL OR payCert LIKE '%' + @paycert + '%') 
                            AND (@record_type IS NULL OR recType = @record_type) 
                            AND (@qs IS NULL OR db_qs.name LIKE '%' + @qs + '%')
                            AND p.date <> null
                END
            ELSE
                BEGIN
                    IF @state = 3
                        BEGIN
                            SELECT TOP(@records) 
                            -- Reference Columns - Used to identify a Record --
                                r.r_id AS 'ref',  
                                grossVal AS 'gross', 
                                payCert AS 'cert', 
                            -- Data Columns for Display --
                                logRef as 'Logging Reference', 
                                db_recTypes.recordName AS 'Record Type', 
                                invNo as 'Invoice No.', 
                                invDate as 'Invoice Date', 
                                accNo as 'Summit Account No.',
                                db_accountNo.name as 'Company Name', 
                                contract as 'Contract No.', 
                                taxStatus as 'Tax Status', 
                                netVal as 'Net Value', 
                                vat as 'V.A.T', 
                                grossVal as 'Gross Value',
                                paycert as 'Payment Certificate No.', 
                                period as 'Period', 
                                paydate as 'Anticipated Payment Date', 
                                db_qs.name as 'QS record sent to', 
                                sentDate as 'Date sent to QS',
                                db_sentMethod.name as 'Sent Via', 
                                returnedDate as 'Date Returned', 
                                r.deleted as 'Removed', 
                                lastModified as 'Last Modified', 
                                creationDate as 'Date Created', 
                                db_users.name as 'Creation User',
                                p.date as 'Date Paid'
                            --  Main Table to Reference --
                                FROM db_records as r
                            -- Proceed with SQL JOINs -- 
                                JOIN db_recTypes
                                ON db_recTypes.recordID = r.recType
                                Join db_accountNo
                                ON db_accountNo.com_id = r.accNo
                                Join db_qs
                                On db_qs.q_id = r.sentTo
                                JOIN db_sentMethod 
                                On db_sentMethod.v_id = r.sentVia
                                Join db_users
                                On db_users.u_id = r.u_id
                                FULL OUTER JOIN db_payments as p
                                ON p.r_id = r.r_id
                            -- Check For the following values
                                WHERE 
                                    (@logging_ref IS NULL OR logRef LIKE '%' + @logging_ref + '%')
                                    AND (@summit_ac_no IS NULL OR accNo LIKE '%' + @summit_ac_no + '%') 
                                    AND (@contract_no IS NULL OR contract LIKE '%' + @contract_no + '%')
                                    AND (@invoice_no IS NULL OR invNo LIKE '%' + @invoice_no + '%') 
                                    AND (@company IS NULL OR db_accountNo.name LIKE '%' + @company + '%')
                                    AND (@paycert IS NULL OR payCert LIKE '%' + @paycert + '%') 
                                    AND (@record_type IS NULL OR recType = @record_type) 
                                    AND (@qs IS NULL OR db_qs.name LIKE '%' + @qs + '%')
                                    AND p.date = null
                        END
                    ELSE
                        Begin
                            SELECT TOP(@records) 
                            -- Reference Columns - Used to identify a Record --
                                r.r_id AS 'ref',  
                                grossVal AS 'gross', 
                                payCert AS 'cert', 
                            -- Data Columns for Display --
                                logRef as 'Logging Reference', 
                                db_recTypes.recordName AS 'Record Type', 
                                invNo as 'Invoice No.', 
                                invDate as 'Invoice Date', 
                                accNo as 'Summit Account No.',
                                db_accountNo.name as 'Company Name', 
                                contract as 'Contract No.', 
                                taxStatus as 'Tax Status', 
                                netVal as 'Net Value', 
                                vat as 'V.A.T', 
                                grossVal as 'Gross Value',
                                paycert as 'Payment Certificate No.', 
                                period as 'Period', 
                                paydate as 'Anticipated Payment Date', 
                                db_qs.name as 'QS record sent to', 
                                sentDate as 'Date sent to QS',
                                db_sentMethod.name as 'Sent Via', 
                                returnedDate as 'Date Returned', 
                                r.deleted as 'Removed', 
                                lastModified as 'Last Modified', 
                                creationDate as 'Date Created', 
                                db_users.name as 'Creation User',
                                p.date as 'Date Paid'
                            --  Main Table to Reference --
                                FROM db_records as r
                            -- Proceed with SQL JOINs -- 
                                JOIN db_recTypes
                                ON db_recTypes.recordID = r.recType
                                Join db_accountNo
                                ON db_accountNo.com_id = r.accNo
                                Join db_qs
                                On db_qs.q_id = r.sentTo
                                JOIN db_sentMethod 
                                On db_sentMethod.v_id = r.sentVia
                                Join db_users
                                On db_users.u_id = r.u_id
                                FULL OUTER JOIN db_payments as p
                                ON p.r_id = r.r_id
                            -- Check For the following values
                                WHERE 
                                    (@logging_ref IS NULL OR logRef LIKE '%' + @logging_ref + '%')
                                    AND (@summit_ac_no IS NULL OR accNo LIKE '%' + @summit_ac_no + '%') 
                                    AND (@contract_no IS NULL OR contract LIKE '%' + @contract_no + '%')
                                    AND (@invoice_no IS NULL OR invNo LIKE '%' + @invoice_no + '%') 
                                    AND (@company IS NULL OR db_accountNo.name LIKE '%' + @company + '%')
                                    AND (@paycert IS NULL OR payCert LIKE '%' + @paycert + '%') 
                                    AND (@record_type IS NULL OR recType = @record_type) 
                                    AND (@qs IS NULL OR db_qs.name LIKE '%' + @qs + '%')
                                    AND r.deleted = 1
                        END
                END
        END

END

似乎导致此问题的表格是db_payments,因为这是引用记录是否已付款的表格。例如(如果记录尚未支付,则此处不存在)

db_payments布局为:

p_id  -  int  - Auto Increment
r_id  -  int  - Link to db_records
date  - date  - date paid

如果您需要db_records表的布局,我可以发送它。

更改查询

现在我收到以下错误:

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

以下是程序:

USE [Sub-Con-Dev]
GO
/****** Object:  StoredProcedure [dbo].[SearchSQL]    Script Date: 22/02/2016 09:17:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      Marcus Gloria
-- Create date: 27/01/2016
-- Description: Gets Search Results
-- =============================================
ALTER PROCEDURE [dbo].[SearchSQL]
    -- Add the parameters for the stored procedure here
    @logging_ref as varchar(50) = NULL,
    @summit_ac_no as varchar(50) = NULL,
    @contract_no as varchar(50) = NULL,
    @invoice_no as varchar(50) = NULL,
    @company as varchar(50) = NULL,
    @paycert as varchar(50) = NULL,
    @record_type as integer = NULL,
    @qs as varchar(50) = NULL,
    @records as int = NULL,
    @state as int = NULL
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @SQL NVARCHAR(MAX) = N'
        SELECT TOP(@records)
            r.r_id as ref,
            grossVal as gross,
            payCert as cert, 
            p.p_id as paid,
            -- Data Columns for Display --
                logRef as "Logging Reference", 
                db_recTypes.recordName AS "Record Type", 
                invNo as "Invoice No.", 
                invDate as "Invoice Date", 
                accNo as "Summit Account No.",
                db_accountNo.name as "Company Name", 
                contract as "Contract No.", 
                taxStatus as "Tax Status", 
                netVal as "Net Value", 
                vat as "V.A.T", 
                grossVal as "Gross Value",
                paycert as "Payment Certificate No.", 
                period as "Period", 
                paydate as "Anticipated Payment Date", 
                db_qs.name as "QS record sent to", 
                sentDate as "Date sent to QS",
                db_sentMethod.name as "Sent Via", 
                returnedDate as "Date Returned", 
                r.deleted as "Removed", 
                lastModified as "Last Modified", 
                creationDate as "Date Created", 
                db_users.name as "Creation User",
                p.date as "Date Paid"
            --  Main Table to Reference --
                FROM db_records as r
            -- Proceed with SQL JOINs -- 
                JOIN db_recTypes
                ON db_recTypes.recordID = r.recType
                Join db_accountNo
                ON db_accountNo.com_id = r.accNo
                Join db_qs
                On db_qs.q_id = r.sentTo
                JOIN db_sentMethod 
                On db_sentMethod.v_id = r.sentVia
                Join db_users
                On db_users.u_id = r.u_id
                FULL OUTER JOIN db_payments as p
                ON p.r_id = r.r_id
                WHERE 1 = 1 '
                 IF (@logging_ref IS NOT NULL) SET @SQL = @SQL + CHAR(13) + CHAR(10) + 'AND logRef LIKE ''%'' + @logging_ref'
                 IF (@summit_ac_no IS NOT NULL) SET @SQL = @SQL + CHAR(13) + CHAR(10) + 'AND accNo LIKE ''%'' + @summit_ac_no'
                 IF (@contract_no IS NOT NULL) SET @SQL = @SQL + CHAR(13) + CHAR(10) + 'AND contract LIKE ''%'' + @contract_no'
                 IF (@invoice_no IS NOT NULL) SET @SQL = @SQL + CHAR(13) + CHAR(10) + 'AND invNo LIKE ''%'' + @invoice_no'
                 IF (@company IS NOT NULL) SET @SQL = @SQL + CHAR(13) + CHAR(10) + 'AND db_accountNo.name LIKE ''%'' + @company'
                 IF (@paycert IS NOT NULL) SET @SQL = @SQL + CHAR(13) + CHAR(10) + 'AND payCert LIKE ''%'' + @paycert'
                 IF (@record_type IS NOT NULL) SET @SQL = @SQL + CHAR(13) + CHAR(10) + 'AND recType LIKE ''%'' + @record_type'
                 IF (@qs IS NOT NULL) SET @SQL = @SQL + CHAR(13) + CHAR(10) + 'AND db_qs.name LIKE ''%'' + @qs'

                DECLARE @lastToken NVARCHAR(100) =
                    (
                    CASE
                        WHEN @state = 1 THEN 'r.deleted = 0'
                        WHEN @state = 2 THEN 'p.date IS NOT NULL' 
                        WHEN @state = 3 THEN 'p.date IS NULL'
                        WHEN @state = 4 THEN 'r.deleted =1'
                    END
                    )
                SET  @SQL = @SQL + CHAR(13) + CHAR(10) + @lastToken

            EXEC sp_executesql @SQL,
                N'@logging_ref as varchar(50), @summit_ac_no as varchar(50) = NULL,
                @contract_no as varchar(50), @invoice_no as varchar(50), @company as varchar(50),
                @paycert as varchar(50), @record_type as integer, @qs as varchar(50),
                @records as int, @state as int',
                @records = @records,
                @logging_ref = @logging_ref,
                @summit_ac_no = @summit_ac_no,
                @contract_no = @contract_no,
                @invoice_no = @invoice_no,
                @company = @company,
                @paycert = @paycert,
                @record_type = @record_type,
                @qs = @qs,
                @records = @records,
                @state = @state     
        END

1 个答案:

答案 0 :(得分:0)

除了建议使用LEFT JOIN不要错过记录之外,我强烈建议使用动态SQL来简化您的过程。正如现在所写,它违反了DRY principle,很难阅读和理解。

由于您的代码在所有分支上执行相同的操作并且还使用了大量过滤器(至少是虚拟的),因此动态SQL很有可能比过多的OR更好。此外,该过程要小得多,并且可以轻松实现滤波器或逻辑的任何变化。

注意 :未进行实际测试

CREATE PROCEDURE [dbo].[SearchSQL]
    -- Add the parameters for the stored procedure here
    @logging_ref as varchar(50) = NULL,
    @summit_ac_no as varchar(50) = NULL,
    @contract_no as varchar(50) = NULL,
    @invoice_no as varchar(50) = NULL,
    @company as varchar(50) = NULL,
    @paycert as varchar(50) = NULL,
    @record_type as integer = NULL,
    @qs as varchar(50) = NULL,
    @records as int = NULL,
    @state as int = NULL
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- no need for alias quotes if they are a full word
    -- some comments omitted for brevity
    DECLARE @SQL NVARCHAR(MAX) = N'
        SELECT TOP(@records) 
            r.r_id AS ref, grossVal AS gross, payCert AS cert, 
            -- omitted for brevity
        FROM db_records as r
            JOIN db_recTypes ON db_recTypes.recordID = r.recType
            Join db_accountNo ON db_accountNo.com_id = r.accNo
            Join db_qs On db_qs.q_id = r.sentTo
            JOIN db_sentMethod On db_sentMethod.v_id = r.sentVia
            Join db_users On db_users.u_id = r.u_id
            LEFT JOIN db_payments as p ON p.r_id = r.r_id
            WHERE 1 = 1 '

        IF (@logging_ref IS NOT NULL) SET @SQL = @SQL + CHAR(13) + CHAR(10) + 'AND logRef LIKE ''%'' + @logging_ref'
        IF (@summit_ac_no IS NOT NULL) SET @SQL = @SQL + CHAR(13) + CHAR(10) + 'AND accNo LIKE ''%'' + @summit_ac_no'
        -- other filters come here
        IF (@qs IS NOT NULL) SET @SQL = @SQL + CHAR(13) + CHAR(10) + 'AND db_qs = @qs'

        DECLARE @lastToken NVARCHAR(100) = 
            (CASE WHEN @state = 1 THEN 'r.deleted = 0'
                  WHEN @state = 2 THEN 'p.date <> null'
                  WHEN @state = 3 THEN 'p.date IS NULL'         -- = NULL is not ok
                  WHEN @state = 4 THEN 'r.deleted = 1'
            END)                                                -- what happens if @state is not 1, 2, 3 or 4?

        SET @SQL = @SQL + CHAR(13) + CHAR(10) + @lastToken

        -- actual execution - PRINT @SQL may be used to check if the query is correct
        EXEC sp_executesql @SQL,
            N'@records INT, @logging_ref as varchar(50), @summit_ac_no as varchar(50) = NULL,
                @contract_no as varchar(50), @invoice_no as varchar(50), @company as varchar(50),
                @paycert as varchar(50), @record_type as integer, @qs as varchar(50),
                @records as int, @state as int',
            @records = @records, @logging_ref = @logging_ref, -- and so on
    END
END