2011-12-08 46 views
0

如何将Q1和Q2合并为Q5(但工作!)? PLSE?我坚持... SQL Server 2008 R2的Sql将WHEN和IF语句与多个参数结合起来

请看看我到目前为止已经试过:

--Q1不无差错地执行: DECLARE @RfDate日期 DECLARE @Description为nvarchar(250) DECLARE @BAccount诠释 SET @RfDate = '{Rf_Date}' SET @Description = {dbo.BankstatementLine_Description |类型=串} SET @BAccount = {dbo.BankAccount_Id}

IF @RfDate <> '' 
     BEGIN 
      SELECT * 
      FROM 
       dbo.BankStatementLine 
      WHERE 
       Date >[email protected] 
      AND 
       FkBankAccount = @BAccount 
      AND 
       IsDebit = 'true' 
      AND 
       Id NOT IN (select FkBankStatementLine from DocumentBankStatementLine) 
     END              
    ELSE 
     BEGIN 
      SELECT * 
      FROM 
       dbo.BankStatementLine 
      WHERE 
       Date <> @RfDate 
      AND 
       FkBankAccount [email protected] 
      AND 
       IsDebit = 'true' 
      AND 
       Id NOT IN (select FkBankStatementLine from DocumentBankStatementLine) 
     END 

--Q2没有错误并执行: DECLARE @RAmount浮 SET @RAmount = {} Rf_Amount

IF @RAmount <>'' 
     BEGIN 
      SELECT Amount 
      FROM  dbo.BankStatementLine 
      WHERE [email protected] 
     END 
    ELSE 
     BEGIN 
      SELECT Amount 
      FROM  dbo.BankStatementLine 

      WHERE Amount<>@RAmount 
      END 

从X-Zero的后帮(必须说明我的性格好然后我的程序技巧btw),我想出了下面的查询,它实际上做它需要做的,除了最后两个AND OR规则。等的使用并不产生任何影响,如果我在场上@RfAccept输入“北京大学”,蒙山描述“0111111111 GPPeking”的条目应该提交,但不.....

DECLARE @RfDate date 
DECLARE @BAccount int 
DECLARE @RfAmount decimal 
DECLARE @RfAcAmount float 
DECLARE @RfKenmerk nvarchar(250) 
DECLARE @RfAccept nvarchar(250) 
SET @RfDate = '{Rf_Date}' 
SET @BAccount = {dbo.BankAccount_Id} 
SET @RfAmount = {Rf_Amount} 
SET @RfAcAmount = {Rf_AccAmount} 
SET @RfKenmerk = {Rf_Betalingskenmerk|type=string} 
SET @RfAccept = {Rf_Acceptgiro|type=string} 

     SELECT * 
     FROM 
      dbo.BankStatementLine 
     WHERE -- All statements can have a value or ''. All statements are not mandatory. 
       isDebit = 1 
     AND Id NOT IN (select FkBankStatementLine from DocumentBankStatementLine) 

     AND fkBankAccount = {dbo.bankAccount_Id} 

     AND ((Date = @RfDate AND @RfDate <> '') 
     OR (Date <> @RfDate AND @RfDate = '')) 

     AND ((Amount = @RfAmount AND @RfAmount <> '') 
     OR (Amount <> @RfAmount AND @RfAmount = '')) 

     AND ((Amount = @RfAcAmount AND @RfAcAmount <> '') 
     OR (Amount <> @RfAcAmount AND @RfAcAmount = '')) 

     AND((Description LIKE '%@RfAccept%' AND @RfAccept<>'')--When Rf_Acceptgiro has a value, the value must be part of the field Description. 
     OR (Description <> @RfAccept AND @RfAccept ='')) --OR Return all Description rules 

     AND((Description LIKE '%@RfKenmerk%' AND @RfKenmerk<>'')--When Rf_Kenmerk has a value, the value must be part of the field Description. 
     OR (Description <> @RfKenmerk AND @RfKenmerk =''))--OR Return all Description rules 
+0

您的代码难以遵循,并且APPEARS试图尝试SQL不支持的内容。如果你能举一个你想要实现的例子,可能会有样本日期,更多的人应该能够帮助你... – Sparky

+0

一个即时评论,在“Q5”中我似乎看到了IF/ELSE/ELSE构造? – BRFennPocock

+0

*我知道,我很抱歉。我在该死的事情上工作了几个小时,并有即将到来的流感。这就是为什么我把问题直接放在网上,今天早上上床睡觉,看起来很新鲜...... *。谢谢大家看看。我在X-Zero的帮助下完成了这个查询(感谢你的教训!),但仍然有一件事要解决...... – Bouwplaats

回答

1

...您似乎有一些问题(并非完全)理解SQL,它只能在一般情况下使用。这些“程序”通常是(虽然不总是)不必要的。您还没有列出您的RDBMS,所以我正在写DB2(不包括语句参数),尽管大多数主要的RDBMS将能够按原样运行大部分

-Q1可以简单地重新写成这样:

SELECT a.* -- note, make sure to list all columns in actual query, '*' is bad form 
FROM dbo.BankStatementLine as a 
EXCEPTION JOIN DocumentBankStatementLine as b 
ON b.fkBankStatementLine = a.id -- this is your 'NOT IN' statement 
WHERE a.isDebit = 'true' -- this is really bad; usea boolean type if available 
         -- otherwise, use `int`/`char` 1/0, with check constraints 
AND a.fkBankAccount = {dbo.bankAccount_id} 
AND (({Rf_Date} IS NOT NULL AND a.Date >= {Rf_Date}) -- please name 'a.date' better... 
    OR ({Rf_Date} IS NULL AND a.Date IS NULL)) -- and use `date` types, and -null- 

-Q2遵循相同的一般原则(尽管它似乎毫无意义,你已经知道的金额):

SELECT amount -- it's -really- bad to use `float` types for money 
       -- use `decimal` or `int` (cents) types instead 
FROM dbo.BankStatementLine 
WHERE (({Rf_Amount} IS NOT NULL AND amount = {Rf_Amount}) 
     OR ({Rf_Amount} IS NULL AND amount IS NULL)) 

- Q3似乎是Q1和Q2的组合(排序):

SELECT a.* 
FROM dbo.BankStatementLine as a -- unless there's a -need- to query a specific 
         -- schema, leave it off; you'll get a bit of flexibility 
EXCEPTION JOIN DocumentBankStatementLine as b 
ON b.fkBankStatementLine = a.id 
WHERE a.isDebit = 'true' 
AND a.fkBankAccount = {dbo.bankAccount_Id} -- this seems like a table name? 
AND (({Rf_Date} IS NOT NULL AND a.Date >= {Rf_Date}) 
    OR ({Rf_Date} IS NULL AND a.Date IS NULL)) 
AND (({Rf_Amount} IS NOT NULL AND amount = {Rf_Amount}) -- didn't know what you 
    OR ({Rf_AccAmount} IS NOT NULL AND amount = {Rf_AccAmount})) -- actually wanted 
      -- But `null`s don't compare to anything, so... 

-Q4:我不确定你实际上可以嵌套if条语句的方式(尤其是Amount-(IF @RAmount <> '')行,你绝对不应该。目前还不清楚(因为Q3)排序是否重要,所以我认为它是。试试这个(请注意,这和原来的版本,只有工作,如果有一个返回行):

SELECT * 
FROM dbo.BankStatementLine 
WHERE amount = COALESCE({RF_Amount}, {RfAccAmount}, (SELECT amount 
                FROM dbo.BankStatementLine 
                WHERE amount IS NOT NULL)) 

-Q5似乎是Q3和Q1的一些奇怪的聚集。同样可重写规则,虽然...如果你想Q2和Q1结合起来,简单地增加了来自WHERE条款(对我们而言,EXCEPTION JOIN s被认为WHERE子句谓词)缺少谓语:

SELECT a.* 
FROM dbo.BankStatementLine as a 
EXCEPTION JOIN DocumentBankStatementLine as b 
ON b.fkBankStatementLine = a.id 
WHERE a.isDebit = 'true' 
AND a.fkBankAccount = {dbo.bankAccount_Id} 
AND (({Rf_Date} IS NOT NULL AND a.Date >= {Rf_Date}) 
    OR ({Rf_Date} IS NULL AND a.Date IS NULL)) 
AND (({Rf_Amount} IS NOT NULL AND amount = {Rf_Amount}) 
     OR ({Rf_Amount} IS NULL AND amount IS NULL)) 

嵌套if陈述/从句总是有些诡,,即使在正常势在必行(Java,C#,C++等)语言。在SQL和类似的情况下,这可能是错误的。你似乎想得太像一个命令式程序员 - 学会在(你的WHEREJOIN子句)中思考,你会好得多。


编辑:

它不返回你所期望的结果,因为比较是区分大小写。对大多数其他编程语言来说也是如此。
请注意,执行LIKE '%<insertValueHere>'(带领%)可防止使用标记(因为优化程序无法知道,其中列中的值出现)。在一个函数中包装列也不会有太大的帮助,但我相信有一些方法可以创建'实体化'/计算指示符,以便该值已经可用。

无论如何,这里是适当的调整。请注意,如果一个列总是有一个值(而不是空值),如果没有提供输入参数,则不需要进行比较。

DECLARE @RfDate date 
DECLARE @BAccount int 
DECLARE @RfAmount decimal 
DECLARE @RfAcAmount float 
DECLARE @RfKenmerk nvarchar(250) 
DECLARE @RfAccept nvarchar(250) 
SET @RfDate = '{Rf_Date}' 
SET @BAccount = {dbo.BankAccount_Id} 
SET @RfAmount = {Rf_Amount} 
SET @RfAcAmount = {Rf_AccAmount} 
SET @RfKenmerk = {Rf_Betalingskenmerk|type=string} 
SET @RfAccept = {Rf_Acceptgiro|type=string} 

SELECT * 
FROM dbo.BankStatementLine 
WHERE isDebit = 1 -- Thank you, this is much better. If numeric, add check constraint. 
AND Id NOT IN (select FkBankStatementLine from DocumentBankStatementLine) 
       -- I am unsure of the performance of this relative to other options 
AND fkBankAccount = {dbo.bankAccount_Id} 
-- Assuming this is an actual date field, non-nullable, you don't need the second comparison 
AND ((Date = @RfDate AND @RfDate <> '') 
    OR (@RfDate = '')) 
-- Don't store amounts as strings, just don't... 
-- Comparison removed for reason above. 
AND ((Amount = @RfAmount AND @RfAmount <> '') 
    OR (@RfAmount = '')) 
-- See notes above 
AND ((Amount = @RfAcAmount AND @RfAcAmount <> '') 
    OR (@RfAcAmount = '')) 
-- If you want all rules/whatever, then... 
-- If it's case insensitive, it's best to -store- it that way. Otherwise, wrap in function 
AND((UPPER(Description) LIKE '%' || UPPER(@RfAccept) || '%' AND @RfAccept<>'') 
    OR (@RfAccept ='')) 
-- Same thing here too. 
AND((Description LIKE '%@RfKenmerk%' AND @RfKenmerk<>'') 
    OR (@RfKenmerk ='')) 

当你输入的是说,一个参数“我不在乎它是什么,给我的一切”,不需要同场比较(和你可能获得更好的性能通过删除比较)。如果您仍然需要检查以确保该字段不为空或空白或其他内容,那么必须在某个时刻检查它 - 无论是在SQL中,还是在获取结果集之后。
此外,如果您在LIKE '%whatever'内部搜索字段,因为它包含多个值(作为分隔符/格式化列表或数据结构),您(很可能)将表设置错误;重新格式化将列放在它自己的表格中(好吧,_usually)。如果它是事物的一部分(比如在书名中搜索一个词),那么你只需要把性能打击一下(好吧,有也许是的方法,但是会导致有些古怪的设计)。

+0

感谢您的广泛答复和解释。我正在使用SQL Server 2008 R2来处理这个问题。是的,我有严重的问题了解SQL,但我愿意学习。除此之外,这就是为什么你们在这里...... ;-)。现在一切正常,除了我在我原来的问题中发布的一个... – Bouwplaats

+0

*“ - 不要将数额存储为字符串,只是不要...”*我知道,但这是为什么:转换数据类型varchar到数字。这就是为什么我使用字符串...这似乎工作,也许在数据库中的错误?我会尽快尝试你的例子!非常感谢你! – Bouwplaats

+0

@Bouwplaats - 这表明你的某个地方有无效数据。根据你存储的号码和方式,这可能会在某个时候回来咬你。找到该数据并**修复**(即使您仍然将其存储为字符串)。存储数字值的原因很多,因为字符不好,但有趣的是''100''小于'“8”或“8”(虽然不小于“008”,但存储格式是_terrible_ - 如果您需要存储'“1000”',会发生什么?)。 –

0

你看上去与SQL Server(它通常有助于指定)工作:

Amount = CASE WHEN @RAmount <> '' THEN @RAmount 
       WHEN @RAcAmount <> '' THEN @RacAmount 
       ELSE Amount END 

是什么,我认为你正在寻找。如果第一个参数不为空,则使用它。如果第一个参数是空的,第二个参数不是,那么使用第二个参数。如果两者均为空,则返回所有值。

+0

亲爱的斯图亚特,谢谢你的努力。是的,SQL服务器。看看我上面提出的。如果它可以更平滑... – Bouwplaats