Multiple CASEs - syntax - sql

Disclaimer: it is probably a trivial mistake.
To solve the query at this link:
Can you return the results with a column named sound that returns
"talk" for humans, "bark" for dogs, and "meow" for cats?
I need to write a CASE with multiple possibilities.
What is wrong with the following syntax?
SELECT *
CASE
WHEN species='human' THEN 'talk'
WHEN species='dog' THEN 'bark'
WHEN species='cat' THEN 'meow'
END AS sound
FROM friends_of_pickles
;
I double-checked the syntax bar reading this question and it seems correct to me?
Where is the mistake?
Thank you very much in advance!

Well, you are missing a comma after *:
SELECT *,
(CASE WHEN species = 'human' THEN 'talk'
WHEN species = 'dog' THEN 'bark'
WHEN species = 'cat' THEN 'meow'
END) AS sound
FROM friends_of_pickles;
However, some databases do not allow * with other columns. So a qualified * is required:
SELECT fop.*,
(CASE WHEN species = 'human' THEN 'talk'
WHEN species = 'dog' THEN 'bark'
WHEN species = 'cat' THEN 'meow'
END) AS sound
FROM friends_of_pickles fop;
To be honest, I recommend a qualifying column names (and *s) in general.

Related

Syntax error on WITH clause

I am working on a web app and there are some long winded stored procedures and just trying to figure something out, I have extracted this part of the stored proc, but cant get it to work. The guy who did this is creating alias after alias.. and I just want to get a section to work it out. Its complaining about the ending but all the curly brackets seem to match. Thanks in advance..
FInputs is another stored procedure.. the whole thing is referred to as BASE.. the result of this was being put in a temp table where its all referred to as U. I am trying to break it down into separate sections.
;WITH Base AS
(
SELECT
*
FROM F_Inputs(1,1,100021)
),
U AS
(
SELECT
ISNULL(q.CoverPK,r.CoverPK) AS CoverPK,
OneLine,
InputPK,
ISNULL(q.InputName,r.InputName) AS InputName,
InputOrdinal,
InputType,
ParentPK,
InputTriggerFK,
ISNULL(q.InputString,r.InputString) AS InputString,
PageNo,
r.RatePK,
RateName,
Rate,
Threshold,
ISNULL(q.Excess,r.Excess) AS Excess,
RateLabel,
RateTip,
Refer,
DivBy,
RateOrdinal,
RateBW,
ngRequired,
ISNULL(q.RateValue,r.RateValue) AS RateValue,
ngClass,
ngPattern,
UnitType,
TableChildren,
TableFirstColumn,
parentRatePK,
listRatePK,
NewParentBW,
NewChildBW,
ISNULL(q.SumInsured,0) AS SumInsured,
ISNULL(q.NoItems,0) AS NoItems,
DisplayBW,
ReturnBW,
StringBW,
r.lblSumInsured,
lblNumber,
SubRateHeading,
TrigSubHeadings,
ISNULL(q.RateTypeFK,r.RateTypeFK) AS RateTypeFK,
0 AS ListNo,
0 AS ListOrdinal,
InputSelectedPK,
InputVis,
CASE
WHEN ISNULL(NewChildBW,0) = 0
THEN 1
WHEN q.RatePK is NOT null
THEN 1
ELSE RateVis
END AS RateVis,
RateStatus,
DiscountFirstRate,
DiscountSubsequentRate,
CoverCalcFK,
TradeFilter,
ngDisabled,
RateGroup,
SectionNo
FROM BASE R
LEFT JOIN QuoteInputs Q
ON q.RatePK = r.RatePK
AND q.ListNo = 0
AND q.QuoteId = 100021 )
Well, I explained the issue in the comments section already. I'm doing it here again, so future readers find the answer more easily.
A WITH clause is part of a query. It creates a view on-the-fly, e.g.:
with toys as (select * from products where type = 'toys') select * from toys;
Without the query at the end, the statement is invalid (and would not make much sense anyhow; if one wanted a permanent view for later use, one would use CREATE VIEW instead).

Access syntax error when using Join

I have those two tables (Members and Now) I just need to make sure that no one in Members is actually in Now. Both tables have different structures but can be joined on firsname, lastname and postalcode.
So I tried this (in access)
SELECT Members.Prenom, Members.Nom, Members.Adresse, Members.[Adresse 2], Members.ville, Members.Province, Members.CodePostal
FROM Members
Left JOIN now ON (members.prenom = now.firstname AND members.nom = now.lastname
AND members.codepostal = now.postcode) WHERE now.id IS NULL
And it gives me a wonderful error message
invalid use of '.' ' ' or '()'. in query expression
May someone enlighten me on what I did wrong?
Pretty sure you cannot use 'now' as a table name, there are certain reserved words that MS Access need (in this case for function Now(), I guess the error message is telling you have missed the parentesis' ()). You could try encasing it in square brackets but I would strongly recommend changing your table name. A useful format I use is to prefix objects such as tblTableName, qryQueryName, rptReportName, frmFormName etc but whatever works for you.
SELECT Members.Prenom, Members.Nom, Members.Adresse, Members.[Adresse 2],
Members.ville, Members.Province, Members.CodePostal
FROM Members
Left JOIN [now] a ON (members.prenom = a.firstname AND members.nom = a.lastname
AND members.codepostal = a.postcode) WHERE a.id IS NULL

Use Case Statement in Join

Hi every one i want to use case statement in join using this query and got error
Select CONVERT(VARCHAR(10), SII.SIDATE,103)DATE,SII.SALEID,SII.ItemName,SI.TenancyID
FROM F_SALESINVOICEITEM SII
INNER JOIN F_SALESINVOICE SI ON SI.SALEID=SII.SALEID
INNER JOIN #TempTableSearch ts ON CASE
WHEN ts.ACCOUNTTYPE = '1' THEN ts.ACCOUNTID=SI.TENANCYID
WHEN ts.ACCOUNTTYPE='2' THEN ts.ACCOUNTID=SI.EMPLOYEEID
WHEN ts.ACCOUNTTYPE='3' THEN ts.ACCOUNTID=SI.SUPPLIERID
WHEN ts.ACCOUNTTYPE='4' THEN ts.ACCOUNTID=SI.SALESCUSTOMERID
Error
Incorrect syntax near '='.
Please help me to solve this error.
IT should be,
ON
ts.ACCOUNTID = CASE
WHEN ts.ACCOUNTTYPE = '1' THEN SI.TENANCYID
WHEN ts.ACCOUNTTYPE = '2' THEN SI.EMPLOYEEID
WHEN ts.ACCOUNTTYPE = '3' THEN SI.SUPPLIERID
WHEN ts.ACCOUNTTYPE = '4' THEN SI.SALESCUSTOMERID
END
Instead of using CASE, I'd much rather do this:
Select CONVERT(VARCHAR(10), SII.SIDATE,103)DATE,SII.SALEID,SII.ItemName,SI.TenancyID
FROM F_SALESINVOICEITEM SII
INNER JOIN F_SALESINVOICE SI ON SI.SALEID=SII.SALEID
INNER JOIN #TempTableSearch ts ON
(ts.ACCOUNTTYPE='1' AND ts.ACCOUNTID=SI.TENANCYID)
OR (ts.ACCOUNTTYPE='2' AND ts.ACCOUNTID=SI.EMPLOYEEID)
OR (ts.ACCOUNTTYPE='3' AND ts.ACCOUNTID=SI.SUPPLIERID)
OR (ts.ACCOUNTTYPE='4' AND ts.ACCOUNTID=SI.SALESCUSTOMERID)
To explain why the query didn't work for you: the syntax of the CASE requires an END at the end of the clause. It would work, as the other solutions proposed suggest, but I find this version to be more convenient to understand - although this part is highly subjective.
you can do this, so you have no chance to misspell something (note that ACCOUNTTYPE and ACCOUNTID used only when needed, you don't have to copy-paste it)
select
convert(varchar(10), SII.SIDATE,103) as DATE,
SII.SALEID, SII.ItemName, SI.TenancyID
from F_SALESINVOICEITEM as SII
inner join F_SALESINVOICE as SI on SI.SALEID = SII.SALEID
outer apply (
'1', SI.TENANCYID
'2', SI.EMPLOYEEID
'3', SI.SUPPLIERID
'4', SI.SALESCUSTOMERID
) as C(ACCOUNTTYPE, ACCOUNTID)
inner join #TempTableSearch as ts on
ts.ACCOUNTTYPE = C.ACCOUNTTYPE and ts.ACCOUNTID = C.ACCOUNTID
You have syntax error. You are missing END there.
You must understand that CASE ... END block is NOT equivalent to IF { } from C-like languages. Much rather this is equivalent to elaborate version of ... ? ... : ... operator from C-like languages. What it means that the WHOLE CASE block must essentially evaluate to single value and that this value has to be the same type no matter which case of the block is executed. This means that:
CASE
WHEN ts.ACCOUNTTYPE = '1' THEN ts.ACCOUNTID=SI.TENANCYID ...
END
Is fundamentally incorrect unless you work on a version of database that will allow you bool value as a value (SQL Server won't allow it for example but I think some of MySQL version used to allow it - not sure about this). You probably should write something like:
CASE
WHEN ts.ACCOUNTTYPE = '1' AND ts.ACCOUNTID=SI.TENANCYID THEN 1
WHEN ts.ACCOUNTTYPE='2' AND ts.ACCOUNTID=SI.EMPLOYEEID THEN 1
WHEN ts.ACCOUNTTYPE='3' AND ts.ACCOUNTID=SI.SUPPLIERID THEN 1
WHEN ts.ACCOUNTTYPE='4' AND ts.ACCOUNTID=SI.SALESCUSTOMERID THEN 1
ELSE 0
END = 1
Notice how the whole CASE block evaluates to 1 or 0 and then it is compared to 1. Of course instead of 4 WHEN's you could use one WHEN with combination of AND's, OR's and ( ) brackets. Of course in this particular case answer by #ppeterka 66 is correct as CASE is not suited for what you really wanted to do - I'm just trying to clarify what CASE really is.

What would be the RegularExpression for the followings?

I have a nomenclature to respect while performing some tasks against the Active Directory.
Here's the nomenclature:
TT-EEE-Mnemonic: if TT = 'GA' or 'GS' or 'PA' or 'PF' -> the schema to create is a "group", with a groupScope of Global.
LT-EEE-Mnemonic: if T = 'A' or 'G' or 'I' or 'N' or 'P' -> the schema to create is a "group", with a groupScope of Domain local.
TTT-EEE-Mnemonic: if TTT* = 'CNX' or 'GST' or 'SVC' -> the shema to create is an "user"
T-SSSS-Mnemonic: if T = 'A' or 'L' or 'M' or 'R' or 'S' -> the schema to create is an "organizationUnit"
What I'm after is a simpler and more effective way than this:
If(dn.Substring(3, 2).Contains("GA") _
Or variable.Substring(3, 2).Contains("GS") _
Or dn.Substring(3, 2).Contains("PA") _
Or dn.Substring(3, 2).Contains("PF")) Then
schema = "group" ' Global'
Else If(dn.Substring(4, 1).Contains("A") _
Or dn.Substring(4, 1).Contains("G") _
Or dn.Substring(4, 1).Contains("I") _
Or dn.Substring(4, 1).Contains("N") _
Or dn.Substring(4, 1).Contains("P")) Then
schema = "group" ' Local'
Else If(dn.Substring(3, 3).Contains("CNX") _
' Well... You get the idea, don't you?
End If
I guess I could use a RegularExpression, or perhaps one for each of the nomenclature I got, something alike.
Is there a way a RegularExpression could become handy in this situation? Or would it be best to stick with that old big-If? Any suggestions are welcome.
Sorry for asking, but I'm not used to use RegularExpression. I know they exist, and bit of what they can do, but that's all.
Thanks!
Your code does not seem to conform your description. With your description, you may want the following regular expression:
^(((GA|GS|PA|PF)|L[AGINP]|(CNX|GST|SVC))-EEE|[ALRMS]-SSSS)$
EDIT: you may want to read up this tutorial about what the regular expression means, specifically look for the "Character classes" and "Grouping and alternatives" sections.
In short, the bar character (i.e. |) is the "OR" operator. The square brackets (i.e. []) are the character class; in other words, "OR" between the characters.
It'd vastly reduce the number of tests and explicit Ors.
If Regex.IsMatch(dn, "^CN=(G[AS]|P[AF])-") Then
schema = "group" ' Global 'damn syntax highlighting
ElseIf Regex.IsMatch(dn, "^CN=L[AGINP]-") Then
schema = "group" ' Local 'damn syntax highlighting
ElseIf Regex.IsMatch(dn, "^CN=(CNX|GST|SVC)-") Then
schema = "user"
ElseIf Regex.IsMatch(dn, "^CN=[ALMRS]-") Then
schema = "organizationUnit"
End If
How about...
Dim Schema As String = Nothing
Select Case dn.SubString(3, 2) ' Am not sure about your index of 3 here!
Case "GA", "GS", "PA", "PS"
Schema = "group"
End Select
If IsNothing(Schema) Then
Select Case ...
End If
etc.

constructing dynamic In Statements with sql

Suppose we need to check three boolean conditions to perform a select query. Let the three flags be 'A', 'B' and 'C'.
If all of the three flags are set to '1' then the query to be generated is
SELECT * FROM Food WHERE Name In ('Apple, 'Biscuit', 'Chocolate');
If only the flags 'A' and 'B' are set to '1' with C set to '0'. Then the following query is generated.
SELECT *
FROM Food
WHERE Name In ('Apple, 'Biscuit');
What is the best way to do it?
SELECT *
FROM Food
WHERE (Name = 'Apple' AND <condition A>)
OR (Name = 'Biscuit' AND <condition B>)
OR (Name = 'Chocolate' AND <condition C>)
Now, while being correct this is not desirable from performance point of view since conditions A, B, and C are not data driven (they don not change from row to row). So you can use permutations of all possible conditions by constructing SQL dynamically - use IN clause and construct its string dynamically.
Yet another solution is assembling final result in the client by running each SELECT separately (pseudo-code):
if A then {
result1 = execute("SELECT * FROM Food WHERE Name = 'Apple')
}
if B then {
result2 = execute("SELECT * FROM Food WHERE Name = 'Biscuit')
}
if C then {
result2 = execute("SELECT * FROM Food WHERE Name = 'Chocolate')
}
result = join(result1, result2, result3)
This solution may work when you have high percentage of cases with just one or two true conditions.
First may be you need to check if all are false and show error. Or may be not if it is acceptable in your case.
Then if these flags are mere bool variables do (pseudocode)
sql = "SELECT *
FROM Food
WHERE Name In (";
if (A) sql += "'Apple', "
if (B) sql += "'Biscuit', "
if (C) sql += "'Chocolate', "
sql = sql.deleteLastCharacter() + ");";
Why don't you include A/B/C in the query?
select * from food where (name = 'Apple' or NOT A) and (name = 'Biscuit' OR NOT B)...
I think this should be read: Dynamic SQL.
The sp_executesql system stored procedure reveals to be pretty useful also.
This is a really complex topic that has many subtle performance implications. You really need to read these excellent articles by Erland Sommarskog:
Dynamic Search Conditions in T-SQL
The Curse and Blessings of Dynamic SQL