0

How to combine Q1 and Q2 into someting like Q5 (But working!) ? Plse? I'M stuck... SQL Server 2008 R2

Please have a look what I've tried so far:

--Q1 does execute without errors: DECLARE @RfDate date DECLARE @Description nvarchar(250) DECLARE @BAccount int SET @RfDate = '{Rf_Date}' SET @Description = {dbo.BankstatementLine_Description|type=string} SET @BAccount = {dbo.BankAccount_Id}

    IF @RfDate <> ''
       BEGIN
          SELECT *
          FROM
              dbo.BankStatementLine
          WHERE 
              Date >=@RfDate
          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 =@BAccount
          AND
              IsDebit = 'true'
          AND
              Id NOT IN (select  FkBankStatementLine from DocumentBankStatementLine)
       END

--Q2 does execute without errors: DECLARE @RAmount float SET @RAmount = {Rf_Amount}

    IF @RAmount <>''
       BEGIN
            SELECT Amount
            FROM      dbo.BankStatementLine
            WHERE Amount=@RAmount
       END
    ELSE 
       BEGIN
            SELECT Amount
            FROM      dbo.BankStatementLine

            WHERE Amount<>@RAmount
            END

After the help from X-Zero (imperative describes my character better then my program skills btw), I came up with the following query which actually does what it needs to do, except for the last two AND OR rules. The LIKE does not have any influence, if I enter ‘PEKING’ in the field @RfAccept, the entries whith Description “0111111111 GPPeking” should be presented, but is does not.....

:

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
3
  • You code is difficult to follow and APPEARS to be attempting something that SQL doesn't support. If you can give an example of what you are trying to achieve, posssibly with sample date, more people should be able to help you out... Commented Dec 8, 2011 at 16:31
  • One immediate comment, in "Q5" I seem to see an IF / ELSE / ELSE construct? Commented Dec 8, 2011 at 16:59
  • I know and I'm sorry for that. I was working for a few hours on the damn thing and had a upcoming flu. Thats why I put the queries straight on the web, went to bed and had fresh look this morning.... Thank you all for having a look. I have the query with the help from X-Zero (Thanks for your lessons!) but still one thing to solve... Commented Dec 12, 2011 at 11:19

2 Answers 2

1

... You seem to have some issues with (not fully) understanding SQL, and all it can do in just general use. These kinds of 'procedures' are generally (although not always) unnecessary. You haven't listed your RDBMS, so I'm writing as if for DB2 (excluding statement parameters), although most major RDBMSs will be able to run the statements largely as is.

-Q1 can be simply re-written as so:

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 follows the same general principles (although it seems pointless; you already know the amount):

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 seems to be a combination of Q1 and Q2 (sort of):

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: I'm not sure you can actually nest if statements that way (especially the Amount-(IF @RAmount <> '') line, and you definitely shouldn't. It's also unclear (because of Q3) whether the ordering is important, so I've assumed it is. Try this instead (please note that this, and your original version, only work if there's one row returned):

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

-Q5 seems to be some wierd conglomeration of Q3 and Q1. The same re-writable rules apply though... And if you want to combine Q2 and Q1, simply add together the missing predicates from the WHERE clauses (for our purposes, EXCEPTION JOINs are considered WHERE clause predicates):

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))

Nesting if statements/clauses is always slightly treacherous, even in normal imperative (Java, C#, C++, etc) languages. In SQL and similar, it's probably just plain wrong. You seem to be thinking too much like an imperative programmer - learn to think in sets (your WHERE and JOIN clauses), and you'll be much better off.


EDIT:

It's not returning the results you expect, because the comparison is case sensitive. This is generally true of most other programming languages, as well.
As a side note, doing a LIKE '%<insertValueHere>' (with a leading %) prevents indicies from being used (because there's no good way for the optimizer to know where in the column the value appears). Wrapping the column in a function isn't going to help much, either, but I believe there are ways to create 'materialized'/computed indicies, such that the value is already available.

In any case, here's the appropriate adjustments. Please note that, if a column will always have a value (as opposed to null), you don't need to do a comparison if the input parameter isn't provided.

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 =''))

When you're inputting a parameter that says, "I don't care what it is, give me everything", the comparison with the field isn't needed (and you may get better performance by removing the comparison). If you still have to check to make sure the field isn't null or blank or something, then you do have to check it at some point - either in the SQL, or after getting the result set.
Also, if you're searching inside the field with LIKE '%whatever' because it contains multiple values (either as a delimiter/formatted list, or a datastructure), you (most likely) have the tables set up incorrectly; reformat to put the column in it's own table(s) (well, _usually). If it's part of the thing (like searching for a word in a book title), you just have to take the performance hit (well, there are maybe ways around this, but result in somewhat wacky designs).

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your extensive answer and explanation. I'm using SQL Server 2008R2 for this matter btw. And yes, I'm having serious issues understanding SQL but I'm willing to learn. Besides that, this is why you guys are here ...;-). Everything works now except for one whitch I posted in my original question...
"-- Don't store amounts as strings, just don't..." I know, but this is why: Error converting data type varchar to numeric. This is why I use a string...That seems to work, maybe an error in the DB? I'll try your example asap! Thank you very much!
@Bouwplaats - That's an indication that you have invalid data somewhere. Depending on what and how you're storing the number, this could come back to bite you badly at some point. Find that data and fix it (even if you still store it as string). There's multiple reasons storing numeric values as character is bad, but the fun one is that "100" sorts as less than "8" or "8 " (although not less than "008", but storing formatting is terrible - what happens if you need to store "1000"?).
0

Looks like you're working with SQL Server (it usually helps to specify):

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

is what I think you're looking for. If the first parameter is not empty, then use it. If the first parameter is empty, and the second one is not, then use the second one. If both are empty, then return all values.

1 Comment

Dear Stuart, Thank you for effort. Yes indeed, sql server. See what I came up with above. If it can be made smoother...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.