Select another column of matching record - Oracle SQL - sql

I have this query:
SELECT
t1.*,
(
SELECT
MIN(t2.e_nm)
FROM
table2 t2
WHERE
t2.c_type = t1.c_type
AND t2.h_level = t1.h_level
AND t2.loop = t1.loop
AND t2.e_id = t1.e_id
HAVING
COUNT(*) = 1
) AS e_nm
FROM
table1 t1
ORDER BY
t1.f_name,
t1.line_num;
When e_nm gets selected from table2 as second parameter, I also want to grab another column of matching record - seq_nm from table1.
How can I do it in the above query?

If the count(*) = 1, then you can use a join with aggregation
SELECT t1.*, t2.e_nm, t2.x
FROM table1 t1 LEFT JOIN
(SELECT t2.c_type, t2.h_level, t2.loop, t2.e_id,
MIN(t2.e_nm) as e_nm, MIN(x) as x
FROM table2 t2
GROUP BY t2.c_type, t2.h_level, t2.loop, t2.e_id
HAVING COUNT(*) = 1
) t2
ON t2.c_type = t1.c_type AND
t2.h_level = t1.h_level AND
t2.loop = t1.loop AND
t2.e_id = t1.e_id
ORDER BY t1.f_name, t1.line_num;
This works because you have the COUNT(*) = 1, so only one row matches. If you didn't, you could still use KEEP:
MIN(x) KEEP (DENSE_RANK FIRST ORDER B t2.e_num ASC) as x

Related

How to retrieve count rows from a table that is filtered using QUALIFY?

To get the number of rows from a table, I can use SELECT COUNT( row-name ) for the joined table.
But this doesn't work if I filter it using QUALIFY ROW_NUMBER() OVER ( PARTITION BY rowx, rowy) = 1
Is there a way to get the total number of rows for a QUALIFY filtered table?
Here is a full example of the query
query = """
SELECT
COUNT(*)
FROM table1
JOIN table2 ON
table1.column1 = table2.column2
JOIN table2 ON
table1.column4 = table3.column5
QUALIFY ROW_NUMBER() OVER
(
PARTITION BY
table3.column6,
table3.column7
) = 1
"""
I also tried
query = """
SELECT
COUNT(*)
FROM (
table1
JOIN table2 ON
table1.column1 = table2.column2
JOIN table2 ON
table1.column4 = table3.column5
QUALIFY ROW_NUMBER() OVER
(
PARTITION BY
table3.column6,
table3.column7
) = 1
)
"""
But it didn't work
Most likely QUALIFY is happening after the COUNT(*) expression is being evaluated. To remedy this, you may take the count of a subquery:
SELECT COUNT(*)
FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY t3.column6, t3.column7) rn
FROM table1 t1
INNER JOIN table2 t2 ON t1.column1 = t2.column2
INNER JOIN table3 t3 ON t1.column4 = t3.column5
) t
WHERE rn = 1;

where column in from another select results with limit (mysql/mariadb)

when i run this query returns all rows that their id exist in select from table2
SELECT * FROM table1 WHERE id in (
SELECT id FROM table2 where name ='aaa'
)
but when i add limit or between to second select :
SELECT * FROM table1 WHERE id in (
SELECT id FROM table2 where name ='aaa' limit 4
)
returns this error :
This version of MariaDB doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
You are using LIMIT without an ORDER BY. This is generally not recommended because that returns an arbitrary set of rows -- and those can change from one execution to another.
You can convert this to a JOIN -- fortunately. If id is not duplicated in table2:
SELECT t1.*
FROM table1 t1 JOIN
(SELECT t2.id
FROM table2 t2
WHERE t2.name = 'aaa'
LIMIT 4
) t2
USING (id);
If id can be duplicated in table2, then:
SELECT t1.*
FROM table1 t1 JOIN
(SELECT DISTINCT t2.id
FROM table2 t2
WHERE t2.name = 'aaa'
LIMIT 4
) t2
USING (id);
Another fun way uses LIMIT:
SELECT t1.*
FROM table1 t1
WHERE id <= ANY (SELECT t2.id
FROM table2
WHERE t2.name = 'aaa'
ORDER BY t2.id
LIMIT 1 OFFSET 3
);
LIMIT is allowed in a scalar subquery.
You can use an analytic function such as ROW_NUMBER() in order to return one row from the subquery. I suppose, this way no problem would occur like raising too many rows issue :
SELECT * FROM
(
SELECT t1.*,
ROW_NUMBER() OVER (ORDER BY t2.id DESC) AS rn
FROM table1 t1
JOIN table2 t2 ON t2.id = t1.id
WHERE t2.name ='aaa'
) t
WHERE rn = 1
P.S.: Btw, id columns are expected to be primary keys of your tables, aren't they ?
Update ( depending on your need in the comment ) Consider using :
SELECT * FROM
(
SELECT j.*,
ROW_NUMBER() OVER (ORDER BY j.id DESC) AS rn2
FROM job_forum j
CROSS JOIN
( SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY t2.id ORDER BY t2.id DESC) AS rn1
FROM table2 t2
WHERE t2.name ='aaa'
AND t2.id = j.id ) t2
WHERE rn1 = 1
) jj
WHERE rn2 <= 10

Count of matching IDs with in C as query

I'm looking to add a column to display a count of all records where the drgpackid matches.
Essentially I want one line in the example provided and a count of how many records have that ID and meet the conditions of the query.
with C as (
select t1.*
from DrgPack t1 join
DrgPack t2
on t1.DrgID = t2.DrgID and t1.CentralMaintFieldMask <> t2.CentralMaintFieldMask
)
select *
from rxworkflowpack
where drgpackid in (select ID from c where CentralMaintFieldMask = 0)
There are a thousand ways to do this, like adding another CTE with the counts and joining to it
with C as (
select t1.*
from DrgPack t1 join
DrgPack t2
on t1.DrgID = t2.DrgID and t1.CentralMaintFieldMask <> t2.CentralMaintFieldMask
),
D as (
select drgpackid, count(*) from rxworkflowpack group by drgpackid)
select *
from rxworkflowpack left join D on rxworkflowpack.drgpackid = d.drgpackid
where drgpackid in (select ID from c where CentralMaintFieldMask = 0)
You can use window function like this:
with C as (
select t1.*
from DrgPack t1 join
DrgPack t2
on t1.DrgID = t2.DrgID and t1.CentralMaintFieldMask <> t2.CentralMaintFieldMask
)
select DISTINCT *, COUNT(*) OVER (PARTITION BY drgpackid) AS CountRecords from rxworkflowpack
where drgpackid in (select ID from c where CentralMaintFieldMask = 0)
You should use < to not double count
select t1.drgpackid, count(*) as cnt
from DrgPack t1
join DrgPack t2
on t1.DrgID = t2.DrgID
and t1.CentralMaintFieldMask < t2.CentralMaintFieldMask
join rxworkflowpack
on rx.ID = t1.drgpackid
and rx.CentralMaintFieldMask = 0
group by t1.drgpackid

TSQL Querying ONLY rows that appeared in specified multiple dates?

So say we have rows
ID | Date
1 1/20
2 1/20
1 1/21
7 1/21
4 1/22
5 1/22
So say I only want to see an ID that appeared in BOTH 1/20 and 1/21.
This should only give me ID 1 since that is the only rows that appears in 1/20 and 1/21. What s the simplest way to achieve this?
I tried doing this:
Select ID, [date]
FROM t1
INNER JOIN (
SELECT ID, Count(*) countRow
FROM t1
Where [date] in(1/20, 1/21)
GROUP BY ID
having count(DISTINCT [Date]) > 1
) aa on t1.id = aa.id
I feel like there's a simple way to achieve this. Any thoughts?
The way you have now is pretty simple. An alternative using exists():
select
t.id
, t.date
from t
where t.date in (1/20, 1/21)
and exists (
select 1
from t as i
where i.id = t.id
and i.date <> t.date
and i.date in (1/20, 1/21)
)
One method uses group by and having:
select id
from t1
where date in ('1/20', '1/21')
group by id
having count(distinct date) = 2;
Of course, if date is really stored as a date, you should fix the format for the date constant to by YYYY-MM-DD.
SELECT ID FROM T1 WHERE Date = '1/20' AND EXISTS (
SELECT ID FROM T1 AS T2 WHERE T2.Date = '1/21' AND
T1.ID = T2.ID)
Not sure it is better
The way you are doing it is pretty standard
Not sure why you need to list the date when that is you where condition
If ID, date is unique then you can use count(*)
Select ID, [date]
FROM t1
INNER JOIN ( SELECT ID
FROM t1
Where [date] = 1/20
intersection
SELECT ID
FROM t1
Where [date] = 1/21
) aa
on t1.id = aa.id
Select ID, [date]
FROM t1
INNER JOIN ( SELECT ID
FROM t1 t1a
join t1 t1b
on t1a.ID = t1b.ID
and t1a.[date] = 1/20
and t1b.[date] = 1/21
) aa
on t1.id = aa.id
If id, value is unique
select id, value
from (select id, value
, count(*) over (partition by id order by value) as cnt
from t
where value in ('a', 'b')
) td
where cnt = 2
order by id, value

SQL Server : Query To Retrieve a Row based on Value in a Column

I have two databases one database is recording tank levels every 1 minute. We have about 30 tanks. The other database contains lookup tables that contain the number of gallons or each tank for a given level.
I have manged to use an INNER JOIN to get data from the lookup table in SQL Server 2012
WITH T1 As
(
SELECT
DateTime, TagName, Value
FROM
INSQL.Runtime.dbo.History
WHERE
DateTime = (SELECT Max(DateTime)
FROM INSQL.Runtime.dbo.History
WHERE TagName LIKE 'LT%')
AND TagName LIKE 'LT%' AND Value <> '0'
),
T2 AS
(
SELECT *
FROM TankSTrappingDB.dbo.StrappingTable
)
SELECT *
FROM T1
LEFT JOIN T2 ON T1.TagName = T2.TagName
WHERE T2.LIT_PV <= T1.Value
However this returns all of the rows from table 2, where the value of the actual level in the tank is less than the value recorded in table 1. I just need the single row from table 2 that is the closest match to the value recorded in table with with the corresponding timestamp.
Instead of joining T2 to T2, you could lookup the MAX(LIT_PV) in T2, where the TAGname matches? But, if you also want other values from the T2 table, you can add another test to the last bit in your SQL
... ...
SELECT *
FROM T1
LEFT JOIN T2 ON T1.TagName = T2.TagName
WHERE T2.LIT_PV <= T1.Value
and T2.LIT_PV in
(select max(T2A.LIT_PV) from T2 T2A
where T1.TagName = T2A.TagName and T2A.LIT_PV <= T1.Value
)
Please try below query. As the sample data is not available I could not test this query.
WITH T1 As
(
SELECT
DateTime, TagName, Value,
ROW_NUMBER() OVER (PARTITION BY TagName ORDER BY DateTime DESC) RN
FROM
INSQL.Runtime.dbo.History
WHERE
TagName LIKE 'LT%' AND Value <> '0'
),
T2 AS
(
SELECT *,
ROW_NUMBER() OVER(ORDER BY T.LIT_PV DESC) RN
FROM TankSTrappingDB.dbo.StrappingTable T
INNER JOIN T1 ON T1.TagName = T.TagName
AND T.LIT_PV <= T1.Value
WHERE T1.RN = 1
)
SELECT *
FROM T1
INNER JOIN T2 ON T1.TagName = T2.TagName
AND T1.RN = T2.RN
WHERE T2.RN = 1