Error while using Case when Alias in join statement - sql

SELECT T1.COL1
,CASE
WHEN T1.COL2 = 111
THEN 'A'
WHEN T1.COL2 = 222
THEN 'B'
ELSE 'C'
END AS DT
,T2.COL1
FROM TABLE1 T1
LEFT JOIN TABLE2 T2 ON T1.COL1 = DT;
error- invalid identifier DT
I want to use and verify the condition using case when alias in join condition which is giving error
NOTE - UPDATED CODE
SELECT T1.COL1
,CASE
WHEN T1.COL2 = 111
THEN 'A'
WHEN T1.COL2 = 222
THEN 'B'
ELSE 'C'
END AS DT
,T2.COL1
FROM TABLE1 T1
LEFT JOIN TABLE2 T2 ON T1.COL1 = CASE
WHEN T1.COL2 = 111
THEN 'A'
WHEN T1.COL2 = 222
THEN 'B'
ELSE 'C'
END;
THis one is working. Any other way other than this?

Unfortunately your new query still makes no sense. As noted previously, your join does not involve any column from TABLE2. Perhaps you obfuscated table names to the point you added this logic error by accident? Here is one way to avoid the huge effort to copy/paste the case expression code.
with cte as (
select *,
case COL2
when 111 then 'A'
when 222 then 'B'
else 'C' end as DT
from dbo.TABLE1
)
select ...
from cte left join dbo.TABLE2 as t2
on cte.Col1 = cte.DT
order by ... ;
If this case expression is commonly used, you could create a computed column and use it for your "join". That does not address the logic flaw but does address reusability.

If you place the assembly of the custom column in a table expression, then the new column gets officially named and can be used on any other expression.
For example:
select t1.*, T2.COL1
from ( -- this is a "table expression" named "t1"
SELECT T1.COL1
,CASE
WHEN T1.COL2 = 111
THEN 'A'
WHEN T1.COL2 = 222
THEN 'B'
ELSE 'C'
END AS DT
FROM TABLE1
) t1
LEFT JOIN TABLE2 T2 ON T2.COL1 = t1.DT;

Related

Include sub query result in select statement in hive

I want subquery result to be part of main query , is this possible in hive
select distinct table1.col1,table1.col2,
calcolumn=
(select count(table1.newcal)
from Table 1 table2
where table2.col1 = table1.col1
and table2.col2 = table1.col2)
from Table 1 table1
I see error as below
Error while compiling statement: FAILED: ParseException line 3:1
cannot recognize input near '(' 'select' 'count' in expression
specification
Use explicit join something like this:
select t1.col1,t1.col2,
count(distinct case when t2.col1 is not null then t1.newcal else null end) as calcolumn
from Table 1 t1
left join table2 t2 on t2.col1 = t1.col1 and t2.col2 = t1.col2
group by t1.col1,t1.col2

Compare a two column with the same table to remove duplicate

A sample table with two column and I need to compare the column 1 and column 2 to the same table records and need to remove the column 1 + column 2 = column 2+column 1.
I tried to do self join and case condition. But its not working
If I understand correctly, you can run a simple select like this if you have all reversed pairs in the table:
select col1, col2
from t
where col1 < col2;
If you have some singletons, then:
select col1, col2
from t
where col1 < col2 or
(col1 > col2 and
not exists (select 1
from t t2
where t2.col1 = t.col2 and
t2.col2 = t.col1
)
);
You can use the except operator.
"EXCEPT returns distinct rows from the left input query that aren't output by the right input query."
SELECT C1, C2 FROM table
Except
SELECT C2, C1 FROM table
Example with your given data set : dbfiddle
I am posting the answer based on oracle database and also the columns are string/varchar:
delete from table where rowid in (
select rowid from table
where column1 || column2 =column2 || column1 )
Feel free to provide more input and we can tweak the answer.
Okay. There might be a simpler way of doing this but this might work as well. {table} is to be replaced with your table name.
;with orderedtable as (select t1.col1, t1.col2, ROW_NUMBER() OVER(ORDER BY t1.col1, t1.col2 ASC) AS rownum
from (select distinct t2.col1, t2.col2 from {table} t2) as t1)
select f1.col1, f1.col2
from orderedtable f1
left join orderedtable f2 on f1.col1 = f2.col2 and f1.col2 = f2.col1 and f1.rownum < f2.rownum
where f2.rownum is null
The SQL below will get the reversed col1 and col2 rows:
select
distinct t2.col1,t1.col2
from
table t1
join
table t2 on t1.col1 = t2.col2 and t1.col2 = t2.col1
And when we get these reversed rows, we can except them with the left join clause, the complete SQL is:
select
t.col1,t.col2
from
table t
left join
(
select
distinct t2.col1,t1.col2
from
table t1
join
table t2 on t1.col1 = t2.col2 and t1.col2 = t2.col1
) tmp on t.col1 = tmp.col1 and t.col2 = tmp.col2
where
tmp.col1 is null
Is it clear?

Compare Two SQL identical Table to find missing records

I am working on SQL 2008. I have two identical tables with same column names.
On Table2, i am missing some records. Some records got deleted in the Table2.
I have to compare Table1 and Table2 and retrieve only missing records from table1.
Use a LEFT JOIN and check for IS NULL like below. where t2.col2 is null will be TRUE only when there are records in table1 which are not present in table2. Which is what you are looking for. [This is a sample code and have no resemblance with your original query]
select t1.col1,t1.col2,t1.col3
from table1 t1
left join table2 t2 on t1.some_column = t2.some_column
where t2.col2 is null
You should use SQL Except. There is no Join involved.
Select * from dbo.TableA
Except
Select * from dbo.TableB
In set theory, the difference of sets A, B (A-B) is the set of elements that belong to A and do not belong to B.
With an " not exists", you have a solution :
select * from Table1 t1 where not exists (select 1 from Table2 t2
where t1.col1 = t2.col1
and t1.col2 = t2.col2
and t1.col3 = t2.col3
and ... // check here all columns ...
)
There is however a little problem in this solution in the case of null values, which can only be tested via a "IS NOT NULL" or "IS NULL", hence the complementary solution:
select * from Table1 t1 where not exists (select 1 from Table2 t2
where (t1.col1 = t2.col1 or (t1.col1 IS NULL and t2.col1 IS NULL))
and (t1.col2 = t2.col2 or (t1.col2 IS NULL and t2.col2 IS NULL))
and (t1.col3 = t2.col3 or (t1.col3 IS NULL and t2.col3 IS NULL))
and ... // check here all columns ...
)

Query regarding formation of SQL query

I have a huge table containing data of the form given below:
Id Col1 Col2 Col3
------------------------
a Fruit1 vitaminA vitaminB
b a price "30"
Now I want to retrieve all fruits containing vitaminA and vitaminB having price less than 30 in SQL. here 'a' is the id which is given to Fruit1. Fruit1 contains VitaminA and vitaminB. Now, the next row indicates that id 'a' has price 30.
My intent is to retrieve all fruits having vitaminA and vitaminB and having price less than 30. Is there a way in SQL by which I may answer this query?
You need to do a join for this:
select t.col1
from t join
t tprice
on t.id = tprice.col1 and
tprice.col2 = 'price'
where ((t.col2 = 'VitaminA' and t.col3 = 'VitaminB') or
(t.col2 = 'VitaminB' and t.col3 = 'VitaminA')
) and
(cast(tprice.col3 as int) <= 30)
This is a very arcane data structure. Can you explain where it comes from?
You will have to use a self-join on your table to get the result.
select t1.id
from yourtable t1
inner join yourtable t2
on t1.id = t2.col1
where
(
t1.col2 = 'vitaminA' and t1.col3 = 'vitaminB'
or t1.col2 = 'vitaminB' and t1.col3 = 'vitaminA'
)
and t2.col2 = 'price'
and cast(t2.col3 as int) < '30';
See SQL Fiddle with Demo
Or you can use a WHERE clause using EXISTS:
select t1.id
from yourtable t1
where
(
t1.col2 = 'vitaminA' and t1.col3 = 'vitaminB'
or t1.col2 = 'vitaminB' and t1.col3 = 'vitaminA'
)
and exists (select t2.col1
from yourtable t2
where t2.col2 = 'price'
and cast(t2.col3 as int) < 30
and t1.id = t2.col1)
See SQL Fiddle with Demo
As a side note, your current data structure is very difficult to work with. If possible you might want to consider restructuring your tables.

Getting next row using SQL

I have 1 table with data thus:
Col1 Col2
------- --------
Admin001 A
Admin001 B
Admin002 C
Admin002 C
Admin003 A
Admin003 C
I need to find all instances of Col2 values with 'A' immediately followed by 'B'. 'A' followed by any other symbol does not count. Is there a way to use SQL to accomplish this?
Environment is DB2 LUW v9.5
Update:
How can I do this if I make the table like below?
Col1 Col2 Col3
---- ------- --------
1 Admin001 A
2 Admin002 C
3 Admin002 C
4 Admin003 A
5 Admin003 C
6 Admin001 B
7 Admin001 A
8 Admin001 C
9 Admin001 B
Given that there is no implicit ordering of a set, then no, there isn't any reliable way to do this. Your data will need to be ordered (perhaps by a third column, or by column 1) for this to make any sense.
SELECT DISTINCT T1.Col2
FROM Table T1 INNER JOIN Table T2
ON T2.Col2 = T1.Col2 AND T2.Col1 = (T1.Col1 + 1)
WHERE T1.Col3 = 'A' AND T2.Col3 = 'B'
Update: As mentioned by Peter Lang, below, this will not work if the sequence in Col1 is interrupted. This version handles that situation and is more guaranteed to produce the correct result although if you're 100% certain the sequence will not be interrupted (that is, if you generate the sequence yourself in the same transaction as the analysis) the first should be faster:
SELECT DISTINCT T1.Col2
FROM Table T1 INNER JOIN Table T2
ON T2.Col2 = T1.Col2
AND T2.Col1 = (SELECT MIN(Col1) FROM Table T3 WHERE T3.Col1 > T1.Col1)
WHERE T1.Col3 = 'A' AND T2.Col3 = 'B'
It looks like you're trying to find out who's grade dropped from A to B, so we'll also assume that you want the results where B follows A for the same admin.
SELECT DISTINCT t1.Col2
FROM table t1
INNER JOIN table t2 ON t1.Col2 = t2.Col2
LEFT OUTER JOIN table t3 ON t1.Col2 = t3.Col2
AND t3.Col1 < t2.Col1 AND t3.Col1 > t1.Col1
WHERE t1.Col3 = 'A'
AND t2.Col3 = 'B' AND t2.Col1 > t1.Col1
AND t3.Col1 IS NULL
This yields any admin who has 'A' followed by 'B'.
The INNER JOIN and the first two expressions in the WHERE clause finds all records where 'B' occurs after 'A'. The left OUTER join and the last expression in the WHERE clause finds all records where there are grades between the A and B, and only takes the records without.
You asked to get these results, one per row, like this:
Col1 Col2 Col3
---- ------- --------
1 Admin001 A
6 Admin001 B
I'm going to adapt the above query the easy way.
I'll simply get the A records, get the B records, and union them:
(SELECT t1.Col1, t1.Col2, t1.Col3
FROM table t1
INNER JOIN table t2 ON t1.Col2 = t2.Col2
LEFT OUTER JOIN table t3 ON t1.Col2 = t3.Col2
AND t3.Col1 < t2.Col1 AND t3.Col1 > t1.Col1
WHERE t1.Col3 = 'A'
AND t2.Col3 = 'B' AND t2.Col1 > t1.Col1
AND t3.Col1 IS NULL)
UNION
(SELECT t2.Col1, t2.Col2, t2.Col3
FROM table t1
INNER JOIN table t2 ON t1.Col2 = t2.Col2
LEFT OUTER JOIN table t3 ON t1.Col2 = t3.Col2
AND t3.Col1 < t2.Col1 AND t3.Col1 > t1.Col1
WHERE t1.Col3 = 'A'
AND t2.Col3 = 'B' AND t2.Col1 > t1.Col1
AND t3.Col1 IS NULL)
ORDER BY Col2, Col1
Notice that we're ordering by Col2 first, then Col1. You may also get more than one set of records for each user.
How are you sorting the columns? If you aren't sorting them, you could get different results each time, as sometimes A would follow B, and sometimes B would follow A. If you are sorting them, you may be able to use an 'exists' test with the sorting expression.
There is no general method of getting the next (or previous) row in SQL, but many implementations provide their own built-in functions to help with that kind of thing. Unfortunately I'm not familiar with DB2.
This query assumes that col1 is some sort of sequence or timestamp for each row. Without it, there's no way to determine if A happened before or after B.
WITH sorted AS
(SELECT col1, col2, col3, ROWNUMBER()
OVER (PARTITION BY col2 ORDER BY col1) AS col4
FROM sometable
)
SELECT a.col1, a.col2, a.col3, b.col1, b.col3
FROM sorted a INNER JOIN sorted b
ON a.col2 = b.col2
WHERE a.col3 = 'A' AND b.col3 = 'B'
AND b.col4 = a.col4 + 1
;
I think the following should work, assuming your updated table layout with 3 columns. (Otherwise it's impossible, because no ordering is available):
select t1.col2
from yourtable t1, yourtable t2
where t1.col3 = 'A'
and t2.col3 = 'B'
and t1.col1 + 1 = t2.col1;