grouping records in one temp table - sql

I have a table where one column has duplicate records but other columns are distinct. so something like this
Code SubCode version status
1234 D1 1 A
1234 D1 0 P
1234 DA 1 A
1234 DB 1 P
5678 BB 1 A
5678 BB 0 P
5678 BP 1 A
5678 BJ 1 A
0987 HH 1 A
So in the above table. subcode and Version are unique values whereas Code is repeated. I want to transfer records from the above table into a temporary table. Only records I would like to transfer are where ALL the subcodes for a code have status of 'A' and I want them in the temp table only once.
So from example above. the temporary table should only have
5678 and 0987 since all the subcodes relative to 5678 have status of 'A' and all subcodes for 0987 (it only has one) have status of A. 1234 is ommited because its subcode 'DB' has status of 'P'
I'd appreciate any help!

Here's my solution
SELECT Code
FROM
(
SELECT
Code,
COUNT(SubCode) as SubCodeCount
SUM(CASE WHEN ACount > 0 THEN 1 ELSE 0 END)
as SubCodeCountWithA
FROM
(
SELECT
Code,
SubCode,
SUM(CASE WHEN Status = 'A' THEN 1 ELSE 0 END)
as ACount
FROM CodeTable
GROUP BY Code, SubCode
) sub
GROUP BY Code
) sub2
WHERE SubCodeCountWithA = SubCodeCount
Let's break it down from the inside out.
SELECT
Code,
SubCode,
SUM(CASE WHEN Status = 'A' THEN 1 ELSE 0 END)
as ACount
FROM CodeTable
GROUP BY Code, SubCode
Group up the codes and subcodes (Each row is a distinct pairing of Code and Subcode). See how many A's occured in each pairing.
SELECT
Code,
COUNT(SubCode) as SubCodeCount
SUM(CASE WHEN ACount > 0 THEN 1 ELSE 0 END)
as SubCodeCountWithA
FROM
--previous
GROUP BY Code
Regroup those pairings by Code (now each row is a Code) and count how many subcodes there are, and how many subcodes had an A.
SELECT Code
FROM
--previous
WHERE SubCodeCountWithA = SubCodeCount
Emit those codes with have the same number of subcodes as subcodes with A's.

It's a little unclear as to whether or not the version column comes into play. For example, do you only want to consider rows with the largest version or if ANY subcde has an "A" should it count. Take 5678, BB for example, where version 1 has an "A" and version 0 has a "B". Is 5678 included because at least one of subcode BB has an "A" or is it because version 1 has an "A".
The following code assumes that you want all codes where every subcode has at least one "A" regardless of the version.
SELECT
T1.code,
T1.subcode,
T1.version,
T1.status
FROM
MyTable T1
WHERE
(
SELECT COUNT(DISTINCT subcode)
FROM MyTable T2
WHERE T2.code = T1.code
) =
(
SELECT COUNT(DISTINCT subcode)
FROM MyTable T3
WHERE T3.code = T1.code AND T3.status = 'A'
)
Performance may be abysmal if your table is large. I'll try to come up with a query that is likely to have better performance since this was off the top of my head.
Also, if you explain the full extent of your problem maybe we can find a way to get rid of that temp table... ;)
Here are two more possible methods. Still a lot of subqueries, but they look like they will perform better than the method above. They are both very similar, although the second one here had a better query plan in my DB. Of course, with limited data and no indexing that's not a great test. You should try all of the methods out and see which is best for your database.
SELECT
T1.code,
T1.subcode,
T1.version,
T1.status
FROM
MyTable T1
WHERE
EXISTS
(
SELECT *
FROM MyTable T2
WHERE T2.code = T1.code
AND T2.status = 'A'
) AND
NOT EXISTS
(
SELECT *
FROM MyTable T3
LEFT OUTER JOIN MyTable T4 ON
T4.code = T3.code AND
T4.subcode = T3.subcode AND
T4.status = 'A'
WHERE T3.code = T1.code
AND T3.status <> 'A'
AND T4.code IS NULL
)
SELECT
T1.code,
T1.subcode,
T1.version,
T1.status
FROM
MyTable T1
WHERE
EXISTS
(
SELECT *
FROM MyTable T2
WHERE T2.code = T1.code
AND T2.status = 'A'
) AND
NOT EXISTS
(
SELECT *
FROM MyTable T3
WHERE T3.code = T1.code
AND T3.status <> 'A'
AND NOT EXISTS
(
SELECT *
FROM MyTable T4
WHERE T4.code = T3.code
AND T4.subcode = T3.subcode
AND T4.status = 'A'
)
)

In your select, add a where clause that reads:
Select [stuff]
From Table T
Where Exists
(Select * From Table
Where Code = T.Code
And Status = 'A')
And Not Exists
(Select * From Table I
Where Code = T.Code
And Not Exists
(Select * From Table
Where Code = I.Code
And SubCode = I.SubCode
And Status = 'A'))
In English,
Show me the rows,
where there is at least one row with status 'A',
and there are NO rows with any specific subcode,
that do not have at least one row with that code/subcode, with status 'A'

INSERT theTempTable (Code)
SELECT t.Code
FROM theTable t
LEFT OUTER JOIN theTable subT ON (t.Code = subT.Code AND subT.status <> 'A')
WHERE subT.Code IS NULL
GROUP BY t.Code
This should do the trick. The logic is a little tricky, but I'll do my best to explain how it is derived.
The outer join combined with the IS NULL check allows you to search for the absence of a criteria. Combine that with the inverse of what you're normally looking for (in this case status = 'A') and the query succeeds when there are no rows that do not match. This is the same as ((there are no rows) OR (all rows match)). Since we know that there are rows due to the other query on the table, all rows must match.

Related

SQL: only return results, after a join, where columns with different words represent the same idea (col 1 'dog' col 2 'hound' = match)

SQL flavor is Mode's unique variation, that said SQL flavor doesn't really matter. If you can show me how to do it in one variety of SQL, I'll at least know what to Google to figure it out in this variation.
I'm joining two tables and trying to identify columns where the status of an item is the same, however the statuses are written differently between the two tables.
Table 1 columns:
Name
Number
Status (available, unavailable, inactive)
Table 2 columns:
Number
Status (unassigned, unavailable, retired)
Available = unassigned, unavailable = unavailable, inactive = retired.
I am trying to first compare available/unassigned line up, inactive/retired line up, etc. Then I'm trying to return only the results where both status columns do not match, but since they use different words for the same idea I just don't know how to do it.
I'd simply recode the Status values to numeric code in a WHERE clause like so
SELECT t1.*,t2.Status FROM t1
LEFT JOIN t2 ON t1.Number = t2.Number
WHERE CASE WHEN t1.Status = 'available' THEN 1
WHEN t1.Status = 'unavailable' THEN 2
WHEN t1.Status = 'inactive' THEN 3
END != CASE WHEN t2.Status = 'unassigned' THEN 1
WHEN t2.Status = 'unavailable' THEN 2
WHEN t2.Status = 'retired' THEN 3
END
http://sqlfiddle.com/#!9/39f243/2
You may use something like the below:
; With StatusMapping AS
(
SElect 'Available' T1Status , 'Unassigned' T2Status
UNION
SELECT 'Unavailable', 'Unavailable'
UNION
SELECT 'Inactive', 'Retired'
)
SELECT *
FROM T1
INNER JOIN StatusMapping M ON M.T1Status = T1.Status
INNER JOIN T2
ON T1.Number = T2.Number
AND T2.Status = M.T2Status

Sql query to group and filter results

I need help with a logic in sql
I have two columns
Ticket no. Status
T1 CC
T1 CP
T1 CR
T1 CO
T2 CP
T2 CR
T2 CO
I want to exclude the entire group of Ticket no. that has the status CC. So in this case, after I run the query I should only get 3 records (i.e. T2 records coz T2 doesn’t have a ticket status CC.
Can anyone help me with a simple sql query please.
One method is not exists:
select t.*
from t
where not exists (select 1
from t t2
where t2.ticket_no = t.ticket_no and t2.status = 'CC'
);
In Teradata, though, the qualify clause might be simpler:
select t.*
from t
qualify sum(case when status = 'CC' then 1 else 0 end) over (partition by ticket_no) = 0;

Join Two Column into New Column

How do I combine both COLUMN2 of table1 and table2?
SELECT COLUMN1, COLUMN2 FROM TABLE1
C1 C2
A 1
SELECT COLUMN1, COLUMN2 FROM TABLE2
C1 C2
A 1
B 2
C 2
C1 C2 C3
A 1 1
B 2 0
C 2 0
I want to have a third column combining column2 of both tables base on column1 which has a value of A, B, C. Then if it's null in either table the value should be 0 Please see third sample for sample result.
So you want to match records from both tables on the basis of key column COLUMN1. If a record exists in only one table display that. COLUMN3 indicates whether the key exists in both tables.
This solution uses FULL OUTER JOIN, so it will work whether a record exists in T1 but not T2 or in T2 but not T1. The coalesce() function displays the first non-null argument.
SELECT coalesce(t1.COLUMN1, t2.COLUMN1) as COLUMN1
, coalesce(t1.COLUMN2, t2.COLUMN2) as COLUMN2
, case when t1.COLUMN1 is not null
and t2.COLUMN1 is not null then 1 else 0 end as COLUMN3
FROM TABLE1 t1
full outer join TABLE2 t2
on t1.COLUMN1 = t2.COLUMN1
Assumption. This query ignores the scenario where t1.COLUMN1 = t2.COLUMN1 but t1.COLUMN2 != t2.COLUMN2. It will just show t1.COLUMN2 in the result set. If this is not the outcome you desire please **edit your question ** to include more sample data and the full required output.
To avoid confusion, lets say table_1 has 2 columns(C1,C2) and table_2 has 2 columns(C3,C4). I just renamed column 1 & 2 of table_2 to column 3 & 4.
From What I understood from your question you want all records of table_2 in the result along with a new column which contains values from table_1 based c3 column.
The requires Table_1 right outer join Table_2 with NVL to display 0 against which value is missing in table_1 (B & C)
Full Query is as follows
SELECT Y.COLUMN_3, Y.COLUMN_4, NVL (X.COLUMN_2, 0)
FROM TABLE_1 X RIGHT OUTER JOIN TABLE_2 Y ON (X.COLUMN_1 = Y.COLUMN_3);
Hope this answers your query. Please mark the answer accepted if this solves your problem.
Please try this code...
select dbo.Table_2.C1,
dbo.Table_2.C2,
[C3] = (select Case when dbo.Table_1.C2 = dbo.Table_2.C2 then 1 else 0 end)
from dbo.Table_2
left join dbo.Table_1 on dbo.Table_1.C1 = dbo.Table_2.C1
This is what you must be looking for
SELECT tbl1.C1,
tbl2.C2,
[C3] =
(
SELECT CASE
WHEN tbl1.C2 Is Null OR tbl2.C2 is null
THEN 0
ELSE 1
END
)
FROM tbl1
INNER JOIN tbl2 ON tbl1.C1 = tbl2.C1;
Try This
select table2.c1,
table2.c2,
case when table1.c2 is null or
table2.c2 is null
then 0 else 1 end c3
from table1,table2 where table1.c1(+)=table2.c1;

Querying two tables to filter data using select case

I have two tables
Table 1 looks like this
ID Repeats
-----------
A 1
A 1
A 0
B 2
B 2
C 2
D 1
Table 2 looks like this
ID values
-----------
A 100
B 200
C 100
D 300
Using a view I need a result like this
ID values Repeats
-------------------
A 100 NA
B 200 2
C 100 2
D 300 1
that means, I want unique ID, its values and Repeats. Repeats value should display NA when there are multiple values against single ID and it should display the Repeats value in case there is single value for repeats.
Initially I needed to display the max value of repeats so I tried the following view
ALTER VIEW [dbo].[BookingView1]
AS
SELECT bv.*, bd2.Repeats FROM Table1 bv
JOIN
(
SELECT distinct bd.id, bd.Repeats FROM table2 bd
JOIN
(
SELECT Id, MAX(Repeats) AS MaxRepeatCount
FROM table2
GROUP BY Id
) bd1
ON bd.Id = bd1.Id
AND bd.Repeats = bd1.MaxRepeatCount
) bd2
ON bv.Id = bd2.Id;
and this returns the correct result but when trying to implement the CASE it fails to return unique ID results. Please help!!
One method uses outer apply:
select t2.*, t1.repeats
from table2 t2 outer apply
(select (case when max(repeats) = min(repeats) then max(repeats)
else 'NA'
end) as repeats
from table1 t1
where t1.id = t2.id
) t1;
Two notes:
This assumes that repeats is a string. If it is a number, you need to cast it to a string.
repeats is not null.
For the sake of completeness, I'm including another approach that will work if repeats is NULL. However, Gordon's answer has a much simpler query plan and should be preferred.
Option 1 (Works with NULLs):
SELECT
t1.ID, t2.[Values],
CASE
WHEN COUNT(*) > 1 THEN 'NA'
ELSE CAST(MAX(Repeats) AS VARCHAR(2))
END Repeats
FROM (
SELECT DISTINCT t1.ID, t1.Repeats
FROM #table1 t1
) t1
LEFT OUTER JOIN #table2 t2
ON t1.ID = t2.ID
GROUP BY t1.ID, t2.[Values]
Option 2 (does not contain explicit subqueries, but does not work with NULLs):
SELECT DISTINCT
t1.ID,
t2.[Values],
CASE
WHEN COUNT(t1.Repeats) OVER (PARTITION BY COUNT(DISTINCT t1.Repeats), t1.ID) > 1 THEN 'NA'
ELSE CAST(t1.Repeats AS VARCHAR(2))
END Repeats
FROM #table1 t1
LEFT OUTER JOIN #table2 t2
ON t1.ID = t2.ID
GROUP BY t1.ID, t2.[Values], t1.Repeats
NOTE:
This may not give desired results if table2 has different values for the same ID.

How to check both table having same row values Even Rows are mismatch?

I have Two table consider tbl1 and tbl2
tbl1
Site
---------
101 - Hold
102 - test
tbl2
Site
---------
101 - Hold
104 - wel
102 - test
I want to check tbl2 data is present in tbl1 . If yes select statement has to return 'Yes' else 'No' ...
EXample
If tbl2 is not having "102-test" then also i have to return 'No'
How can i achieve this.
You do this by looking for a non-match and using this information:
select (case when count(*) = 0 then 'Yes' else 'No' end)
from tbl2 t2
where not exists (select 1 from tbl1 where t1.site = t2.site);
The count(*) guarantees that exactly one row is returned, containing yes or no.
SELECT
CASE EXISTS( SELECT Id FROM tbl2 WHERE Id IN (SELECT Id FROM tbl1))
THEN 'Yes'
ELSE 'No'
END
Checking if tbl2 data exists in tbl1 and returning back the site with value either Yes or No when tbl2 exists in tbl1 or not.
No need to use any aggregate and you have information about all tbl1 site's - which is what you wanted to achieve (according to your question).
SELECT
a.site, CASE WHEN b.site IS NOT NULL THEN 'Yes' ELSE 'No END AS value_exists
FROM
tbl1 a
LEFT JOIN tbl2 b ON
a.site = b.site
If you have duplicate values in tbl1 then you might want to consider adding DISTINCT or GROUP BY clause.