繁体   English   中英

SQL过程-根据状态从另一个表中选择数据

[英]Sql Procedure - Select data depending on state from another table

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

  • 有偿和无偿
  • 仅付费
  • 仅未付款
  • 删除记录

然后,它执行一个选择查询,该查询将提取与那些记录状态匹配的所有记录,这是查询:

    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

除了建议不要使用LEFT JOIN来丢失记录,我还强烈建议您通过使用动态SQL来简化您的过程。 就像现在写的那样,它违反了DRY原理 ,很难阅读和理解。

由于您的代码在所有分支上都做同样的事情,并且还使用了许多过滤器(至少实际上是使用过滤器),因此动态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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM