Teradata Scenario - sql

Given:-
When DML_OPeration is Insert "I" then B=0 When DML_OPeration is
Delete "D" then B will hold the value of A of inserted record
Condition :-
if COUNT OF 'I' = Count of 'D', then we don't need those records. for example : ID=111
Find latest insert('I') DML_operation
ID A B DML_Operation
1 111 1 0 I
2 111 2 1 D
3 111 3 0 I
4 111 4 3 D
5 111 5 0 I
6 111 6 5 D
7 111 7 0 I
8 222 8 0 I
9 333 9 0 I
10 333 10 9 D
11 444 11 0 I
12 444 12 11 D
13 444 13 0 I
14 111 14 7 D
15 333 15 0 I
16 444 16 0 I
17 444 17 13 D
Desire Output
ID A B DML_Operation
-------------
222 8 0 I
333 15 0 I
444 16 0 I
My logic which is not working
sel ID, Max(A) from xyz
group by ID
having count(c='I') <> COUNT(c='D')

does you find like below
select ID, Max(A) from xyz
group by ID
having sum(case when c='I' then 1 else 0 end) <> sum(case when c='D' then 1 else 0 end)

How about using case?
select ID, Max(A)
from xyz
group by ID
having sum( case when c = 'I' then 1 else 0 end) <> sum(case when c = 'D' then 1 else 0 end)
Or:
having sum(case when c = 'I' then 1
when c = 'D' then -1
else 0
end) <> 0

This will find all 'I' rows without matching 'D' row:
SELECT *
FROM mytab AS t1
WHERE DML_Operation = 'I'
AND NOT EXISTS
( SELECT *
FROM mytab AS t2
WHERE t2.id = t1.id
AND t2.b = t1.a
AND DML_Operation = 'D'
)

Related

SQL: subset data: select id when time_id for id satisfy a condition from another column

I have a data (dt) in SQL like the following:
ID time_id act rd
11 1 1 1
11 2 4 1
11 3 7 0
12 1 8 1
12 2 2 0
12 3 4 1
12 4 3 1
12 5 4 1
13 1 4 1
13 2 1 0
15 1 3 1
16 1 8 0
16 2 8 0
16 3 8 0
16 4 8 0
16 5 8 0
and I want to take the subset of this data such that only ids (and their corresponding time_id, act, rd) that has time_id == 5 is retained. The desired output is the following
ID time_id act rd
12 1 8 1
12 2 2 0
12 3 4 1
12 4 3 1
12 5 4 1
16 1 8 0
16 2 8 0
16 3 8 0
16 4 8 0
16 5 8 0
I know I should use having clause somehow but have not been successful so far (returns me empty outputs). below is my attempt:
SELECT * FROM dt
GROUP BY ID
Having min(time_id) == 5;
This query:
select id from tablename where time_id = 5
returns all the ids that you want in the results.
Use it with the operator IN:
select *
from tablename
where id in (select id from tablename where time_id = 5)
You can use a correlated subquery with exists:
select t.*
from t
where exists (select 1 from t t2 where t2.id = t.id and t2.time_id = 5);
WITH temp AS
(
SELECT id FROM tab WHERE time_id = 5
)
SELECT * FROM tab t join temp tp on(t.id=tp.id);
check this query
select * from table t1 join (select distinct ID from table t where time_id = 5) t2 on t1.id =t2.id;

Concetating results from Oracle table with several criterias

This is a tough one. I've read about concatating values from multible rows in a table, but can't find anything on how to go about the task set before me.
I'm not an oracle-man, and untill now have only made simple select queries, so I'm at a loss here.
In a huge oracle database table (severel hundred millions of rows) containing laboratory results, I need to select information on specific requisitions, that meet a specific criteria.
Criteria: For the same ReqNo, Analysis A B and C must be present with an answer, if they are, any instance of the answer to analysis X, Y or Z should be selected
Table contents:
ReqNo Ana Answer
1 A 7
1 B 14
1 C 18
1 X 250
2 A 8
2 X 35
2 Y 125
3 A 8
3 B 16
3 C 20
3 Z 100
4 X 115
4 Y 355
5 A 6
5 B 15
5 C 22
5 X 300
5 Y 108
5 C 88
Desired result:
ReqNo A B C X Y Z
1 7 14 18 250
3 8 16 20 100
5 6 15 22 300 108 88
leaving out ReqNo 2 and 4, since they don't meet the A/B/C criteria.
Is that even possible?
You may first filter the records that have all 3 (A,B and C) and then use PIVOT to convert them to columns for those which satisfy the criteria.
with req
AS
(
select reqno from t where ana IN ('A','B','C')
GROUP BY reqno HAVING
count(DISTINCT ana) = 3
)
select * FROM
(
select * from t where
exists ( select 1 from req r where t.reqno = r.reqno )
)
PIVOT(
min(answer) for ana in ('A' as A, 'B' as B, 'C' as C,
'X' as X, 'Y' as Y, 'Z' as Z)
) ORDER BY reqno;
Demo
I would just use conditional aggregation:
select reqno,
max(case when Ana = 'A' then Answer end) as a,
max(case when Ana = 'B' then Answer end) as b,
max(case when Ana = 'C' then Answer end) as c,
max(case when Ana = 'X' then Answer end) as x,
max(case when Ana = 'Y' then Answer end) as y,
max(case when Ana = 'Z' then Answer end) as z
from t
group by reqno
having sum(case when Ana = 'A' then 1 else 0 end) > 0 and
sum(case when Ana = 'B' then 1 else 0 end) > 0 and
sum(case when Ana = 'C' then 1 else 0 end) > 0 ;
Given that you don't seem to have duplicates, you can simplify the having to:
having sum(case when Ana in ('A', 'B', 'C') then 1 else 0 end) = 3

SQL recursive hierarchy

I am struggling to get one recursive CTE to work as desired but still with no chance..
So, I have the following similar table structures:
tblMapping:
map_id | type_id | name | parent_id
1 1 A1 0
2 1 A2 0
3 1 A3 1
4 1 A4 3
5 2 B1 0
6 2 B2 5
7 2 B3 6
8 1 A5 4
9 2 B4 0
tblRoleGroup:
role_group_id | type_id | map_id | desc_id
1 1 0 null
1 2 0 null
2 1 3 1
2 2 6 0
3 1 8 1
3 2 9 1
In tblRoleGroup, the desc_id field means:
null - allow all (used only in combination with map_id=0)
0 - allow all from parent including parent
1 - allow only current node
Still in tblRoleGroup if map_id=0 then the query should get all elements from same type_id
The query result should look like this:
role_group_id | type_id | map_id | path
1 1 1 A1
1 1 2 A2
1 1 3 A1.A3
1 1 4 A1.A3.A4
1 1 8 A1.A3.A4.A5
1 2 5 B1
1 2 6 B1.B2
1 2 7 B1.B2.B3
1 2 9 B4
2 1 3 A1.A3
2 2 6 B1.B2
2 2 7 B1.B2.B3
3 1 8 A1.A3.A4.A5
3 2 9 B4
The query below solves only a part of the expected result, but I wasn't able to make it work as the expected result..
WITH Hierarchy(map_id, type_id, name, Path) AS
(
SELECT t.map_id, t.type_id, t.name, CAST(t.name AS varchar(MAX)) AS Expr1
FROM dbo.tblMapping AS t
LEFT JOIN dbo.tblMapping AS t1 ON t1.map_id = t.parent_id
WHERE (t1.parent_id=0)
UNION ALL
SELECT t.map_id, t.type_id, t.name, CAST(h.Path + '.' + t.name AS varchar(MAX)) AS Expr1
FROM Hierarchy AS h
JOIN dbo.tblMapping AS t ON t.parent_id = h.map_id
)
SELECT h.map_id, h.type_id, t.role_group_id, h.Path AS Path
FROM Hierarchy AS h
LEFT JOIN dbo.tblRoleGroup t ON t.map_id = h.map_id
Could someone help me on this?
Thank you
At first I create a function that brings all descendants of passed map_id:
CREATE FUNCTION mapping (#map_id int)
RETURNS TABLE
AS
RETURN
(
WITH rec AS (
SELECT map_id,
[type_id],
CAST(name as nvarchar(max)) as name,
parent_id
FROM tblMapping
WHERE map_id = #map_id
UNION ALL
SELECT m.map_id,
m.[type_id],
r.name+'.'+m.name,
m.parent_id
FROM rec r
INNER JOIN tblMapping m
ON m.parent_id = r.map_id
)
SELECT *
FROM rec
);
GO
Then run this:
;WITH rec AS (
SELECT map_id,
[type_id],
CAST(name as nvarchar(max)) as name,
parent_id
FROM tblMapping
WHERE parent_id=0
UNION ALL
SELECT m.map_id,
m.[type_id],
r.name+'.'+m.name,
m.parent_id
FROM rec r
INNER JOIN tblMapping m
ON m.parent_id = r.map_id
)
SELECT t.role_group_id,
r.[type_id],
r.map_id,
r.name as [path]
FROM tblRoleGroup t
CROSS JOIN rec r
WHERE r.[type_id] = CASE WHEN t.desc_id IS NULL AND t.map_id = 0 THEN t.[type_id] ELSE NULL END
OR r.map_id = CASE WHEN t.desc_id = 1 THEN t.map_id ELSE NULL END
OR r.map_id IN (
SELECT map_id
FROM dbo.mapping (CASE WHEN t.desc_id = 0 THEN t.map_id ELSE NULL END)
)
ORDER BY role_group_id, r.[type_id], r.map_id
Will give you:
role_group_id type_id map_id path
1 1 1 A1
1 1 2 A2
1 1 3 A1.A3
1 1 4 A1.A3.A4
1 1 8 A1.A3.A4.A5
1 2 5 B1
1 2 6 B1.B2
1 2 7 B1.B2.B3
1 2 9 B4
2 1 3 A1.A3
2 2 6 B1.B2
2 2 7 B1.B2.B3
3 1 8 A1.A3.A4.A5
3 2 9 B4

how to double count column which already counted

Please help me to solve the problem
My real table is:
id group numberOfLevel(counted column)
1 10 4
2 10 2
3 11 2
4 11 1
5 11 3
6 11 2
7 21 1
8 21 2
9 30 1
10 40 2
But i want to show:
group 1st_level 2nd_level 3rd_level over4th_level
10 0 1 0 1
11 1 2 1 0
21 1 1 0 0
30 1 0 0 0
40 0 1 0 0
Which way do i need to use to show the table?
Please share experience ?
This is a basic pivot query, an ANSII SQL case expession can be used in such a query,
and it should work on most databases:
select group_nr,
sum( case when numberOfLevel = 1 then 1 else 0 end ) As level_1st,
sum( case when numberOfLevel = 2 then 1 else 0 end ) As level_2nd,
sum( case when numberOfLevel = 3 then 1 else 0 end ) As level_3rd,
sum( case when numberOfLevel >= 4 then 1 else 0 end ) As over4th_level
from table1
group by group_nr
;
demo: http://sqlfiddle.com/#!2/4bd04/4
Don't use group as a column name, because group is a keyword in SQL.

How to group sums by weekday in MySQL?

I have a table like this:
id | timestamp | type
-----------------------
1 2010-11-20 A
2 2010-11-20 A
3 2010-11-20 B
4 2010-11-21 A
5 2010-11-21 C
6 2010-11-27 B
and I need to count the rows for each type, grouped by weekday; like this:
weekday | A | B | C
--------------------------
5 2 2 0 -- the B column equals 2 because nov 20 and nov 27 are saturday
6 1 0 1
What would be the simplest solution for this?
I don't mind using views, variables, subqueries, etc.
Use:
SELECT WEEKDAY(t.timestamp) AS weekday,
SUM(CASE WHEN t.type = 'A' THEN 1 ELSE 0 END) AS a,
SUM(CASE WHEN t.type = 'B' THEN 1 ELSE 0 END) AS b,
SUM(CASE WHEN t.type = 'C' THEN 1 ELSE 0 END) AS c
FROM YOUR_TABLE t
GROUP BY WEEKDAY(t.timestamp)