SQL query with a CASE statement - sql

I am still learning much about SQL queries but found myself stuck on this. I understand I could break this Query into two queries to get the desired functionality, but i would like to do it in one if possible. My problem lies within the Case clause. i have a condition if the in and out columns are between the selected date range, i want to do myColumnValue + .5 else keep it the same. myColumnValue is a double. The problem is, when i add 'myColumnValue + some constant' to the THEN and Else Clause, it makes the update have now effect on the row, but when i remove it and have only constants in it... it works fine. I am using SQL server 2008. I know I am probably missing some part of the query where I have to reinitialize the myColumnValue as a varible, but I am unsure how to do this. If anyone can give me some direction if keeping this into one query, or if there is an easier way to do this without cases, any guidance would be greatly appreciated. Thanks in advance.
UPDATE myTableName
SET myColumnValue=
(CASE
WHEN((In <= '12/1/2011' ) AND (Out >= '12/7/2011' ))
THEN(myColumnValue + .5 )
ELSE(myColumnValue)
END)
WHERE ID = 'someIndex'

The right way is moving case condition to where clause:
UPDATE myTableName
SET myColumnValue=myColumnValue + .5
WHERE ID = 'someIndex'
AND ([In] <= '12/1/2011' )
AND ([Out] >= '12/7/2011' )

Related

Postgresql - CASE/WHEN with wrong return

I tried to use CASE/WHEN inside Postgresql to check two colums, but the results are odd.
As it's shown in the image below, all the lines where "gain_value" is 8 AND "patrimony_value" have a higher value return a wrong result.
This is my statement:
select stop_value, gain_value, patrimony_value,
case
when patrimony_value >= gain_value then 1
else 2
end
from copy.copy_stop_gain csg
Since it's a pretty straightforwad "if/else", i'm really not sure what i could be doing wrong.
Can anyone show me where is my mistake?
Try casting string values to numbers (or perhaps change column type in schema)...
select stop_value, gain_value, patrimony_value,
case
when patrimony_value::INTEGER >= gain_value::INTEGER then 1
else 2
end
from copy.copy_stop_gain csg

Hive - SELECT inside WHEN clause of CASE function gives an error

I am trying to write a query in Hive with a Case statement in which the condition depends on one of the values in the current row (whether or not it is equal to its predecessor). I want to evaluate it on the fly, this way, therefore requiring a nested query, not by making it another column first and comparing 2 columns. (I was able to do the latter, but that's really second-best). Does anyone know how to make this work?
Thanks.
My query:
SELECT * ,
CASE
WHEN
(SELECT lag(field_with_duplicates,1) over (order by field_with_duplicates) FROM my_table b
WHERE b.id=a.id) = a.field_with_duplicates
THEN “Duplicate”
ELSE “”
END as Duplicate_Indicator
FROM my_table a
Error:
java.sql.SQLException: org.apache.spark.sql.AnalysisException: cannot recognize input near 'SELECT' 'lag' '(' in expression specification; line 4 pos 9
Notes:
The reason I needed the complicated 'lag' function is that the unique Id's in the table are not consecutive, but I don't think that's where it's at: I tested by substituting another simpler inner query and got the same error message.
Speaking of 'duplicates', I did search on this issue before posting, but the only SELECT's inside CASE's I found were in the THEN statement, and if that works the same, it suggests mine should work too.
You do not need the subquery inside CASE:
SELECT a.* ,
CASE
WHEN prev_field_with_duplicates = field_with_duplicates
THEN “Duplicate”
ELSE “”
END as Duplicate_Indicator
FROM (select a.*,
lag(field_with_duplicates,1) over (order by field_with_duplicates) as prev_field_with_duplicates
from my_table a
)a
or even you can use lag() inside CASE instead without subquery at all (I'm not sure if it will work in all Hive versions ):
CASE
WHEN lag(field_with_duplicates,1) over (order by field_with_duplicates) = field_with_duplicates
THEN “Duplicate”
ELSE “”
END as Duplicate_Indicator
Thanks to #MatBailie for the answer in his comment. Don't I feel silly...
Resolved

SQL - ORDER BY Works in Sub-query, But Fails in Full Query

I'm trying to set up a dynamic query to populate average payments over a dynamic period of months. I have a working query, but it provides the months out of order.
I assign the months to a variable, #columns, and use that in the main query to determine the fields for a PIVOT command. The following is how the variable is set up;
As can be seen, the months are out of order.
But, if I run just the sub-query;
It orders fine.
What's going on? Any thoughts?
Thanx in advance!
(hopefully, the images come out as I want)
In your outer select you need to specify ORDER BY to guarantee the order. Currently you are only ordering your derived table and not the final query.
SELECT #columns += ',' + QUOTENAME(Eff_Period)
FROM
(derived table) AS Raw_Data
ORDER BY Eff_Period
PRINT #columns
SELECT #columns == ',' + QUOTENAME (Eff_period)
FROM ( ... ) as Raw_Data
ORDER BY Eff_period
I think the subquery is unnecessary if all you need additionally is to concatenate the text ',' + + QUOTENAME(Eff_Period). But you can just do this without a subquery. Also, the TOP 100 PERCENT does not work as others have pointed out, it's not needed in any case.
SELECT #column += ',' + QUOTENAME(Eff_Period)
FROM Members_Data AS Mbrs
INNER JOIN Claims_Data AS Clms
ON Mbrs.Eff_Period = REPLACE(CONVERT(nvarchar(7), Clms.Date_of_Service, 121), '-', '')
WHERE YEAR(Clms.Date_of_Service) = 2016
GROUP BY Mbrs.Eff_Period
ORDER BY Eff_Period
Also... I had to re-type the entire text from the screenshot. Not a big deal to some people, but this is one reason we prefer the text versus screenshot.
Yes, the outside ORDER BY was the answer.
I thought ORDER BY had to use field names and, as there was none, I had no clue how to put it in there. I tried using the ordinal, 1, unfortunately that only gave me the final value in the concatenated list.
But, it appears that it can take Eff_Period in the outside SELECT; perhaps because it's a unique name from the JOIN.
However, that answered the problem I was having. A problem that arose from an answer that I thought fixed an overlying problem, but I have discovered does not. I'm trying to figure that out at this time.
Thanx to everyone who responded!

SQL Where statement with CASE variable

Im sorry I do not have a complete query because my original is actually very long but I feel you may be able to spot where I have an error in my syntax. Basically I declare 2 variables and if one variable is blank I need the where statement to be where the field is not in the other variable.
Where dnCP_FromServiceDate >= '01/01/2016' And
dnCP_FromServiceDate <= '01/31/2016' And
dnCP_RecordStatus <> 'V'
AND CASE WHEN #inpDXIN = '' THEN
predxDiagnosisCode not in (#inpDXNOTIN)
ELSE predxDiagnosisCode IN (#inpDXIN)
END
Even if I could get a snippet of a query using a similar statement i can figure mine out but i cant find anything similar. Any help is greatly appreciated
In general, you don't want to use case in a where clause. Instead, just use regular boolean logic:
Where dnCP_FromServiceDate >= '2016-01-01' and
dnCP_FromServiceDate <= '2016-01-31' and
dnCP_RecordStatus <> 'V' and
( (#inpDXIN = '' and predxDiagnosisCode <> #inpDXNOTIN) or
(#inpDXIN <> '' and predxDiagnosisCode IN (#inpDXIN)
)
Notes:
Use ISO/ANSI standard date formats. Much less ambiguous.
IN (#var) is the same as = #var. You cannot pass an in list through a variable. If you need that functionality, then ask another question.
Most dialects of SQL do not allow boolean expressions to be returned from a case. The above gets around this "limitation".

Regex: does a SQL statement include a WHERE clause?

I need a regex that will determine if a given SQL statement has a WHERE clause. My problem is that the passed SQL statements will most likely be complex, so I can not rely on just the existence of the word WHERE in the statement.
For example this should match
SELECT Contacts.ID
, CASE WHEN (Contacts.Firstname IS NULL) THEN ''
ELSE CAST(Contacts.Firstname AS varchar)
END AS Firstname
, CASE WHEN (Contacts.Lastname IS NULL) THEN ''
ELSE CAST(Contacts.Lastname AS varchar)
END AS Lastname
, CASE WHEN (tbl_ContactExtras.Prequalified=-1 OR
tbl_ContactExtras.Prequalified IS NULL) THEN ''
WHEN tbl_ContactExtras.Prequalified=0 THEN 'No'
WHEN tbl_ContactExtras.Prequalified=1 THEN 'Yes - Other'
WHEN tbl_ContactExtras.Prequalified=2 THEN 'Yes'
ELSE CAST(tbl_ContactExtras.Prequalified AS varchar)
END AS Prequalified
FROM contacts
LEFT JOIN tbl_ContactExtras
ON tbl_ContactExtras.ContactID = Contacts.ID
WHERE (Contacts.Firstname LIKE 'Bob%')
and this should not match:
SELECT Contacts.ID
, CASE WHEN (Contacts.Firstname IS NULL) THEN ''
ELSE CAST(Contacts.Firstname AS varchar)
END AS Firstname
, CASE WHEN (Contacts.Lastname IS NULL) THEN ''
ELSE CAST(Contacts.Lastname AS varchar)
END AS Lastname
, CASE WHEN (tbl_ContactExtras.Prequalified=-1 OR
tbl_ContactExtras.Prequalified IS NULL) THEN ''
WHEN tbl_ContactExtras.Prequalified=0 THEN 'No'
WHEN tbl_ContactExtras.Prequalified=1 THEN 'Yes - Other'
WHEN tbl_ContactExtras.Prequalified=2 THEN 'Yes'
ELSE CAST(tbl_ContactExtras.Prequalified AS varchar)
END AS Prequalified
FROM contacts
LEFT JOIN tbl_ContactExtras
ON tbl_ContactExtras.ContactID = Contacts.ID
Those are examples of some of the simpler statements: a statement could have up to 30 CASE statements in it, or it could have none at all.
I need to programmatically add WHERE parameters, but doing this correctly requires knowing whether a WHERE clause is already present.
Any idea on a regex that would work for this? If not, any other ideas on how to tell the two apart?
Thanks,
This is not possible, since a WHERE clause may be arbitrarily nested inside the FROM clause.
This may not catch all cases but you may find you can catch most of them just by finding the last from and the last where in the statement.
if the where is after the from, then it has a where clause. If the where is before the from (or there is no where at all), then no where clause exists.
Sometimes, it's okay to leave restrictions or limitations in your code, as long as they're properly documented.
For example, I've worked on a project before that parsed SQL and we discovered it didn't handle things like between:
where recdate between '2010-01-01' and '2010-12-31'
Rather than spend a bucket-load of money fixing the problem (and probably introducing bugs on the way), we simply published it as a restriction and told everyone they had to change it to:
where recdate >= '2010-01-01'
and recdate <= '2010-12-31'
Problem solved. While it's good to keep customers happy, you don't have to cater to every whim :-)
Other than that, you need an SQL parser, and SQL is not a pretty language to parse, trust me on that one.
Are all of the joins the same? If so you could find the index of all or part of the FROM statement (perhaps using a regex to be tolerant of slight differences in syntax and whitespace) and then look for the occurrence of the word WHERE after that index.
In general you would be better off using a parser. But if this is just a one off thing and the statements are all fairly similar then the above approach should be okay.
Regex is not designed to do this. Parsing SQL properly requires matching balanced parentheses (and other matching pairs, such as quotes), something regex is not designed to do (and pure regex isn't even equipped to; PCRE can but it's not pretty).
Instead, just write a basic state machine or something to parse it.
What's the problem you're trying to solve? Are you trying to determine if it's safe to add constraints to these existing queries?
For example, if you've got this query
...
where foo = 'bar'
then you know it's safe to add
and bat = 'quux'
but if you don't have a WHERE clause already, then you have to do it as
where bat = 'quux'
Is that the problem you're trying to solve? If so, can you make every SQL query you're working with have a WHERE clause by adding a "WHERE 0=0" to those queries that don't have one? Then you know in your post-process phase that every query already has one.
This is just a guess, of course. Your question sounded like that might be the larger issue.