Mutliple values for IN clause with CASE in Redshift - sql

I am trying to run this query where IN clause uses CASE to choose values between two cases.
The issue is with the hard coded value('aaa','bbb'). I cannot add multiple values inside THEN so it act as regular IN values. The hard code values will be dynamic as I will pass a variable for it.
select kdo.field0
from tb1 data1 inner join tb2 kdo
on kdo.field1 = 'xxx'
and kdo.field2::DATE >='2017-08-01'::DATE
and kdo.field0
in (case when 'asd'!='' then 'aaa','bbb'
else tb2.field0 end);
Also, I used a sub-query select inside THEN to get specific hard code values but it is also of no avail. Using single hard-coded value obviously works as usual.

Move your CASE outside IN:
select kdo.field0
from tb1 data1 inner join tb2 kdo
on kdo.field1 = 'xxx'
and kdo.field2::DATE >='2017-08-01'::DATE
and case when 'asd'!='' then kdo.field0 in ('aaa','bbb')
else kdo.field0=tb2.field0 end;
however I'm not sure what do you mean by 'asd'!='' since 'asd' is a string and this will always return true
also, else tb2.field0 end); part in your statement is not an array option, it's a column name so I assume this just translates to kdo.field0=tb2.field0 because if the previous case option is false you want to check if kdo.field0 is equal to any of values in tb2.field0 which is basically a join condition

Related

SQL - if something then do this if nothing do nothing

I have a column with many nulls in table 1, but now and then there is a value. If there is a value, I want to go to table 2 and take the the corresponding value from there. This should create an extra column called user_original:
CASE
WHEN table1.user_changed IS NOT NULL
THEN table2.user_original
ELSE -- do nothing
END as user_original
I basically want to replace
is nothing
Is this correct ? How can this be done? Is there a better way?
do you mean you need below
CASE
WHEN table1.user_changed IS NOT NULL
THEN table2.user_original
END as user_original
Do you want a correlated subquery?
(CASE WHEN table1.user_changed IS NOT NULL
THEN (SELECT table2.user_original FROM table2 WHERE table2.? = table1.?)
END) as user_original
The ? is for the columns that identifying "corresponding" values.
If this is the case, you can probably simplify this to:
(SELECT table2.user_original FROM table2 WHERE table2.? = table1.?) as user_original
My guess is there will be no matching value if the original value is NULL.

adding a sub query to a case statement in hive

I hope you can help. I have the below query, which has a case statement.
I want to say:
IF the domain is in the other table, then return the domain name, else, mark it as 'other'
I am using Hive & get the error:
Unsupported SubQuery Expression 'cleandomain': Currently SubQuery expressions are only allowed as Where Clause predicates
Is there some other way I can achieve the same?
SELECT *,
CASE
WHEN cleandomain IN (SELECT cleandomain
FROM keenek1.daily_top_doms) THEN cleandomain
ELSE 'other'
END AS status
FROM (SELECT hour,.....
One possible solution is using in_file(string str, string filename) function.
Put the list of domains in the text file, one domain per line, txt file and call in_file function in the CASE statement:
CASE
WHEN in_file(cleandomain,'file/path/daily_top_doms.txt') THEN cleandomain
ELSE 'other'
END AS status
Another solution is to aggregate the list of domains into array in the subquery, join using cross join and use array_contains(). This may work much faster if the list is not too big:
with dom as (
SELECT collect_set(cleandomain) dom
FROM keenek1.daily_top_doms
)
select
case when array_contains(d.dom, s.cleardomain) then s.cleandomain
else 'other'
end as status
from (your query) s cross join dom d --one row cross join

sql if parameter is true, add a where clause

I have a long stored procedure with cross joins and left joins. I have several parameters in this table. On the last two left joins, I want to add a conditional where clause based on a parameter.
I will call this parameter #NonCAT which basically category code. The where clause that I am trying to implement just weeds out the non-category codes. The codes for the non-category codes are as follows:
CATCOD IN ('0', '114', '214', '314', '414', '614')
So any of those numbers in the CATCOD column are considered noncat codes.
Otherwise, if they are included, like if they are not in a where clause, they are considered cat codes. so here is my where clause in the last two left joins:
AND CASE
WHEN il.CATCOD IN ('0', '114', '214', '314', '414', '614')
THEN 'NonCAT'
ELSE 'CAT'
END = #NonCAT
This works just fine if I am trying to extract the category codes the #NonCAT variable is just a varchar(20) and it's set to 'NonCAT' as its value for now for the sake of testing. With the where clause in place, I am going to extract the non-cat codes.
I want a conditional statement, say if the variable #NonCAT = 'CAT', I want to omit that where clause. How do I go about doing this? I have tried various case statements and it's harder than it sounds. Thanks so much for the help.
Edit: I tried using iff statement in a where clause for example,
AND (IF #NonCAT = 'NonCAT'
BEGIN
CASE
WHEN il.CATCOD IN ('0', '114', '214', '314', '414', '614')
THEN 'NonCAT'
ELSE 'CAT'
END = #NonCAT
END)
Seems like that doesn't work. I can use an IF statement at the very begging of the code as a flag but that doesn't seem very efficient because I would have to rewrite the whole thing without a where clause if that makes sense.
You mean something like this?
WHERE ( ( #nonCAT = 'nonCAT' AND il.CATCOD IN ('0', '114', '214', '314', '414', '614') )
OR ( (ISNULL(#nonCAT,'') <> 'nonCAT' ))

Assign a case value to a column rather than an alias

This should be a simple one, but I have not found any solution:
The normal way is using an alias like this:
CASE WHEN ac_code='T' THEN 'time' ELSE 'purchase' END as alias
When using alias in conjunction with UNION ALL this causes problem because the alias is not treated the same way as the other columns.
Using an alias to assign the value is not working. It is still treated as alias, though it has the column name.
CASE WHEN ac_code='T' THEN 'time' ELSE 'purchase' END as ac_subject
I want to assign a value to a column based on a condition.
CASE WHEN ac_code='T' THEN ac_subject ='time' ELSE ac_subject='purchase' END
Now I get the error message
UNION types character varying and boolean cannot be matched
How can I assign a value to a column in a case statement without using an alias in the column (shared by other columns in UNION)?
Here is the whole (simplified) query:
SELECT hr_id,
CASE WHEN hr_subject='' THEN code_name ELSE hr_subject END
FROM hr
LEFT JOIN code ON code_id=hr_code
WHERE hr_job='123'
UNION ALL
SELECT po_id,
CASE WHEN po_subject='' THEN code_name ELSE po_subject END
FROM po
LEFT JOIN code ON code_id=po_code
WHERE po_job='123'
UNION ALL
SELECT ac_id,
CASE WHEN ac_code='T' THEN ac_subject='time' ELSE ac_subject='purchase' END
FROM ac
WHERE ac_job='123'
There is no alias in your presented query. You are confusing terms. This would be a column alias:
CASE WHEN hr_subject='' THEN code_name ELSE hr_subject END AS ac_subject
In a UNION query, the number of columns, column names and data types in the returned set are determined by the first row. All appended rows have to match the row type. Column names in appended rows (including aliases) are just noise and ignored. Maybe useful for documentation, nothing else.
The = operator does not assign anything in a SELECT query. It's the equality operator that returns a boolean value. TRUE if both operands are equal, etc. This returns a boolean value: ac_subject='time' Hence your error message:
UNION types character varying and boolean cannot be matched
The only way to "assign" a value to a particular output column in this query is to include it at the right position in the SELECT list.
The information in the question is incomplete, but I suspect you are also confusing the empty string ('') with the NULL value. A distinction that you need to understand before doing anything else with relational databases. Maybe start here. In this case you would rather use COALESCE to provide a default for NULL values:
SELECT hr_id, COALESCE(hr_subject, code_name) AS ac_subject
FROM hr
LEFT JOIN code ON code_id=hr_code
WHERE hr_job = '123'
UNION ALL
SELECT po_id, COALESCE(po_subject, code_name)
FROM po
LEFT JOIN code ON code_id=po_code
WHERE po_job = '123'
UNION ALL
SELECT ac_id, CASE WHEN ac_code = 'T' THEN 'time'::varchar ELSE 'purchase' END
FROM ac
WHERE ac_job = '123'
Just an educated guess, assuming type varchar. You should have added table qualification to column names to clarify their origin. Or table definitions to clarify everything.
The CASE expression is supposed to return a value, e.g. 'time'.
Your value is another expression subject ='time' which is a boolean (true or false).
Is this on purpose? Does the other query you glue with UNION have a boolean in that place, too? Probably not, and this is what the DBMS complains about.
I found the problem.
CASE WHEN hr_subject=’’ THEN code_name ELSE hr_subject END
The columns code_name and hr_subject was different length. This caused the unpredictable result. I think that aliases can work now.
Thank you for your support.

how can I replace blank value with zero in MS-Acess

I have below query in Ms-Access but I want to replace Blank value with zero but I can't get proper answer. Is there any way to replace blank value in zero.
(SELECT
SUM(IIF(Review.TotalPrincipalPayments,0,Review.TotalPrincipalPayments))+
SUM(IIF(Review.TotalInterestPayments,0,Review.TotalInterestPayments ))
FROM
tblReviewScalars as Review
INNER JOIN tblReportVectors AS Report ON(Review.LoanID=Report.LoanID)
WHERE Report.AP_Indicator="A" AND Report.CashFlowDate=#6/5/2011# AND Review.AsofDate=#6/5/2011# AND ( Review.CreditRating =ReviewMain.CreditRating)) AS [Cash Collected During the Period],
I assume TotalPrincipalPayments and TotalInterestPayments are both numeric types, hence the 'blanks' in question is the NULL value.
In SQL, the set function SUM will disregard NULL values, unless all values resolve to NULL in which case NULL is returned (erroneously and the error is with SQL not Access for a change :)
To use a simple example, SELECT SUM(a) FROM T; will only return NULL when a IS NULL is TRUE for all rows of T or when T is empty. Therefore, you can move the 'replace NULL with zero' logic outside of the SUM() function. Noting that "NULLs propagate" in calculations, you will need to handle NULL for each SUM().
You haven't posted the whole of your query e.g. the source of the correlation name ('table alias') ReviewMain is not showm. But it seems clear you are constructing a derived table named "Cash Collected During the Period", in which case your calculated column needs an AS clause ('column alias') such as TotalPayments e.g.
...
(
SELECT IIF(SUM(Review.TotalPrincipalPayments) IS NULL, 0, SUM(Review.TotalPrincipalPayments))
+ IIF(SUM(Review.TotalInterestPayments) IS NULL, 0, SUM(Review.TotalInterestPayments))
AS TotalPayments
FROM tblReviewScalars as Review
INNER JOIN tblReportVectors AS Report
ON Review.LoanID = Report.LoanID
WHERE Report.AP_Indicator = 'A'
AND Report.CashFlowDate = #2011-05-06#
AND Review.AsofDate = #2011-05-06#
AND Review.CreditRating = ReviewMain.CreditRating
) AS [Cash Collected During the Period], ...
An alternative to #onedaywhen's answer is to use the nz function, which is specifically for null-substitution:
SELECT
SUM(NZ(Review.TotalPrincipalPayments,0))+
SUM(NZ(Review.TotalInterestPayments,0))
...
As onedaywhen pointed out, this is functionally equivalent to putting the function outside the aggregate, which may perform better (the function is called once, rather than once per un-aggregated row):
SELECT
NZ(SUM(Review.TotalPrincipalPayments),0)+
NZ(SUM(Review.TotalInterestPayments),0)
...
To change a null value to a zero in an Access 2010 database, open your table, go to design view, click on the field and set the default value to: =0.