convert case statement to where condition - amazon-redshift

I am trying to convert this case statement:
(CASE UPPER(dc.source_name) WHEN 'DART' THEN dc.ad_campaign_id ELSE dc.cfid END) AS rodeo_order_id
into a condition in the where clause.
Any help is appreciated!
Thanks,
S

This is not possible. The Case-Expression in the Select clause decides the content of a returned column for all returned rows while the where-clause defines which rows are returned.
You have to give a better explanation what problem you have in order to get an answer.

I have to admit I don't understand need for this, but something like this might be the solution (assuming ad_campaign_id and cfid are of the same type):
select dc1.ad_campaign_id
from <table> dc1
where UPPER(dc.source_name) = 'DART'
UNION
select dc2.cfid
from <table> dc2
where UPPER(dc.source_name) != 'DART'

Related

What does CASE WHEN EXISTS (select * from table) do? Is there a better way to write this?

I need to resolve an issue with performance of the following query (not my code). It's a section of a larger stored procedure. This particular part is taking a very long time to execute (I just cancelled it after 20 mins) and I don't understand the intent of the case statement in the code. My research to date has only shown examples of checking for a particular column using schema tables, or checking if any records exists using select 1...
This is doing select *. Can someone help me to understand the case when exists subquery part of this query and if there is a better (more efficient in terms of time to execute) way to write this?
INSERT INTO [PaymentStage06]
SELECT
CASE
WHEN EXISTS (SELECT *
FROM [transaction] AS [MPT])
THEN 'Y'
ELSE 'N'
END AS [DuplicateReleased],
[MPT].[participantid] AS [ParticipantID],
[MPT].[courseid] AS [CourseID],
[MPT].[session] AS [SessionID],
[MPT].[feedbackcompletedid] AS [TransactionID],
GETDATE() AS [Refreshed]
FROM
[transaction] AS [MPT]
Many thanks.
Andrew
I've looked for examples of "case when exists(select *" but haven't found anything concrete. My guess is it's either checking for the existence of ANY record in that table (in which case why not just select 1), OR it's checking for a match based on all columns, but both of those seem pointless when the outer query is working on the same table. I'm obviously missing the point :)
This is the estimated execution plan https://www.brentozar.com/pastetheplan/?id=H1VMU7Goj
According to the execution plan, it is performing a 'left semi join' operation between the inner and outer query. This appears to be like an intersect query... but still pointless because it's working on the 1 table.

PostgreSQL use function result in ORDER BY

Is there a way to use the results of a function call in the order by clause?
My current attempt (I've also tried some slight variations).
SELECT it.item_type_id, it.asset_tag, split_part(it.asset_tag, 'ASSET', 2)::INT as tag_num
FROM serials.item_types it
WHERE it.asset_tag LIKE 'ASSET%'
ORDER BY split_part(it.asset_tag, 'ASSET', 2)::INT;
While my general assumption is that this can't be done, I wanted to know if there was a way to accomplish this that I wasn't thinking of.
EDIT: The query above gives the following error [22P02] ERROR: invalid input syntax for integer: "******"
Your query is generally OK, the problem is that for some row the result of split_part(it.asset_tag, 'ASSET', 2) is the string ******. And that string cannot be cast to an integer.
You may want to remove the order by and the cast in the select list and add a where split_part(it.asset_tag, 'ASSET', 2) = '******', for instance, to narrow down that data issue.
Once that is resolved, having such a function in the order by list is perfectly fine. The quoted section of the documentation in the comments on the question is referring to applying an order by clause to the results of UNION, INTERSECTION, etc. queries. In other words, the order by found in this query:
(select column1 as result_column1 from table1
union
select column2 from table 2)
order by result_column1
can only refer to the accumulated result columns, not to expressions on individual rows.

Will Postgres' DISTINCT function always return null as the first element?

I'm selecting distinct values from tables thru Java's JDBC connector and it seems that NULL value (if there's any) is always the first row in the ResultSet.
I need to remove this NULL from the List where I load this ResultSet. The logic looks only at the first element and if it's null then ignores it.
I'm not using any ORDER BY in the query, can I still trust that logic? I can't find any reference in Postgres' documentation about this.
You can add a check for NOT NULL. Simply like
select distinct columnName
from Tablename
where columnName IS NOT NULL
Also if you are not providing the ORDER BY clause then then order in which you are going to get the result is not guaranteed, hence you can not rely on it. So it is better and recommended to provide the ORDER BY clause if you want your result output in a particular output(i.e., ascending or descending)
If you are looking for a reference Postgresql document then it says:
If ORDER BY is not given, the rows are returned in whatever order the
system finds fastest to produce.
If it is not stated in the manual, I wouldn't trust it. However, just for fun and try to figure out what logic is being used, running the following query does bring the NULL (for no apparent reason) to the top, while all other values are in an apparent random order:
with t(n) as (values (1),(2),(1),(3),(null),(8),(0))
select distinct * from t
However, cross joining the table with a modified version of itself brings two NULLs to the top, but random NULLs dispersed througout the resultset. So it doesn't seem to have a clear-cut logic clumping all NULL values at the top.
with t(n) as (values (1),(2),(1),(3),(null),(8),(0))
select distinct * from t
cross join (select n+3 from t) t2

Using [WHERE, IN, LEN, IN] TSQL

I am trying to write a simple statement in my where clause but I don't believe I have the syntax right. The query looks to search whether these ID's are in this column but I am not sure if I can use IN twice in the same line? Could anyone please provide some feed back. Thanks!
WHERE... AND (tableA.ColumnA in LEN(LTRIM(RTRIM(TableB.ColumnB))) in (5,7) )
I am getting some syntax errors near the second IN and can't figure out if this is the correct way to approach this?
When you use IN with a column, it needs to be a sub-select, but here is a correct way you can do it (Wes's sub-select still has the same syntax error):
WHERE... AND (tableA.ColumnA in (
SELECT ColumnB FROM TableB WHERE LEN(LTRIM(RTRIM(TableB.ColumnB))) in (5,7)
))
Try using a subquery instead.
WHERE... AND (SELECT TA.ColumnA
FROM TableA TA
WHERE TA.ColumnA IN LEN(LTRIM(RTRIM(TABLEB.ColumnB))) IN (5,7)
using join
join TableB
on TableB.ColumnB = tableA.ColumnA
and LEN(LTRIM(RTRIM(TableB.ColumnB))) in (5,7)

Postgres undefined column when using CASE

Using this SQL, I can cast a boolean column to a text:
SELECT *, (CASE WHEN bars.some_cond THEN 'Yes' ELSE 'No' END) AS some_cond_alpha
FROM "foos"
INNER JOIN "bars" ON "bars"."id" = "foos"."bar_id";
So why do I get a PG::UndefinedColumn: ERROR: column "some_cond_alpha" does not exist when I try to use it in a WHERE clause?
SELECT *, (CASE WHEN bars.some_cond THEN 'Yes' ELSE 'No' END) AS some_cond_alpha
FROM "foos"
INNER JOIN "bars" ON "bars"."id" = "foos"."bar_id"
WHERE (some_cond_alpha ILIKE '%y%');
This is because the column is created on-the-fly and does not exist. Possibly in later editions of PG it will, but right now you can not refer to an alias'd column in the WHERE clause, although for some reason you can refer to the alias'd column in the GROUP BY clause (don't ask me why they more friendly in the GROUP BY)
To get around this, I would make the query into a subquery and then query the column OUTSIDE the subquery as follows:
select *
from (
SELECT *, (CASE WHEN bars.some_cond THEN 'Yes' ELSE 'No' END) AS some_cond_alpha
FROM "foos"
INNER JOIN "bars" ON "bars"."id" = "foos"."bar_id"
) x
WHERE (x.some_cond_alpha ILIKE '%y%')
NOTE: It is possible at some point in the future you will be able to refer to an alias'd column in the WHERE clause. In prior versions, you could not refer to the alias in the GROUP BY clause but since 9.4 + it is possible...
SQL evaluates queries in a rather counterintuitive way. It starts with the FROM and WHERE clauses, and only hits the SELECT towards the end. So aliases defined in the SELECT don't exist yet when we're in the WHERE. You need to do a subquery if you want to have access to an alias, as shown in Walker Farrow's answer.
When I read an SQL query, I try to do so in roughly this order:
Start at the FROM. You can generally read one table/view/subquery at a time from left to right (or top to bottom, depending on how the code is laid out); it's normally not permissible for one item to refer to something that hasn't been mentioned yet.
Go down, clause by clause, in the order they're written. Again, read from left to right, top to bottom; nothing should reference anything that hasn't been defined yet. Stop right before you hit ORDER BY or something which can only go after ORDER BY (if there is no ORDER BY/etc., stop at the end).
Jump up to the SELECT and read it.
Go back down to where you were and resume reading.
If at any point you see a subquery, apply this algorithm recursively.
If the query begins with WITH RECURSIVE, go read the Postgres docs for 20 minutes and figure it out.