I have a PostgreSQL that works which uses multiple joins, and one column that is the result of a calculation. From the result of that query I need to extract the rows in which that one column is maximal, and there might be many. If there weren't, I could just ORDER BY that_column DESC LIMIT 1; and I found that if I just needed to that on an existing database table, I could just do:
SELECT columns FROM table_name
WHERE that_coulmn = (SELECT MAX(that_column) FROM table_name)
However, that's also not the case. I have a query that is like this:
SELECT z.xyz, (x.aa- x.bb) * y.qq as that_column
FROM table_1 x
JOIN table_2 y ON x.foo = y.foo
JOIN table_3 z ON y.bar = z.bar
JOIN table_4 w ON w.baz = z.baz
where x.aa IS NOT NULL
Now, this works. Now I need to know how I put that as a subquery and take from that the z.xyz from the rows where that_column is maximal. Any help?
Maybe is this?
SELECT MAX(thatmax.that_column) as theMax FROM (
SELECT z.xyz, (x.aa- x.bb) * y.qq as that_column
FROM table_1 x
JOIN table_2 y ON x.foo = y.foo
JOIN table_3 z ON y.bar = z.bar
JOIN table_4 w ON w.baz = z.baz
where x.aa IS NOT NULL
) thatmax
if you need to select other columns as your output:
select * from (
select *, dense() over(order by (x.aa- x.bb) * y.qq desc) as that_column
from table_1 x
join table_2 y ON x.foo = y.foo
join table_3 z ON y.bar = z.bar
join table_4 w ON w.baz = z.baz
where x.aa IS NOT NULL
) t where that_column = 1
I found it!
I took that as a subquery, used [rank](https://www.postgresqltutorial.com/postgresql-rank-function/) to rank by thatColumn and then put that in another subquery to take the ones with rank=1
SELECT xyz
FROM
(xyz, thatColumn, RANK() OVER(ORDER BY thatColumn DESC) FROM (
-- the subquery in the question
)
) AS highest_and_rank
WHERE thatColumnRank = 1
Thank you to everyone who tried to help. You're awesome.
Related
I don't know, if I made good title, but please let me visualize this.
So I have two tables and for given case I need to select row where payment currency was ONLY in EUR.
Correct document Id's will be: 2, 3, 4, 5
These are overall bigger tables with 900k+ records.
Can you please suggest me how query should look?
use correlated subquery with not exists
select distinct a.document_id from tablename a inner join tablename b b on a.document_id=b.payment_docid
where not exists
(select 1 from tablename b1 where b1.payment_docid=b.payment_docid and currency<>'EUR')
Try this query:
select payment_docId from MyTable
group by payment_docId
having max(currency) = 'EUR'
and min(currency) = 'EUR'
or you could use having count(*) = 1 with min or max as well.
use corelated subquery
select t1.* from table2 as t1
where exists( select 1 from table2 t2 where t1.payment_docid=t2.payment_docid
having count(distinct currency)=1)
and currency='EUR'
It is possible to use INNER JOIN with the following conditions to get all rows:
SELECT
pd.payment_doc_id
, pd.currency
FROM DocTable dt
INNER JOIN PaymentDocs pd
ON dt.document_id = pd.payment_doc_id AND pd.currency IN ('EUR')
If you want distinct rows, then you can apply operator GROUP BY:
SELECT
pd.payment_doc_id
, pd.currency
FROM DocTable dt
INNER JOIN PaymentDocs pd
ON dt.document_id = pd.payment_doc_id AND pd.currency IN ('EUR')
GROUP BY pd.payment_doc_id
, pd.currency
Aggregation is the only efficient want :
select doc_id
from table t
group by doc_id
having min(currency) = max(currency) and min(currency) = 'EUR';
I have these two tables:
T1:
ref || Name
===========
1 || A
2 || B
3 || C
4 || D
5 || E
And
T2:
ref || Name
===========
1 || w
2 || x
6 || y
7 || z
I need this result:
Name1 || Name2
==============
A || w
B || x
C || y
D || z
E || NULL
I mean some kind of full outer join, on column ref, that will not produce NULL value until there is not any record.
The priority of join is with the values that have same ref, and if row count of tables are not equal, there are some NULL results
Use UPD: here is how you may combine values by values count from different tables:
with t1_values as (
SELECT
name,
row_number() over (order by ref) as position
FROM #t1
),
t2_values as (
SELECT
name,
row_number() over (order by ref) as position
FROM #t2
)
SELECT
t1_values.name as name1,
t2_values.name as name2
FROM t1_values
left JOIN t2_values on t1_values.position = t2_values.position
This is very complicated. You want rows that match to match. Then you want unmatched rows to match unmatched rows by position, and then everything else.
with matches as (
select distinct t1.ref
from t1
where exists (select 1 from t2 where t2.ref = t1.ref)
),
tt1 as (
select t1.*, m.ref as match_ref,
row_number() over (partition by m.ref order by t1.ref) as alt_ref
from t1 left join
matches m
on t1.ref = m.ref
),
tt2 as (
select t2.*, m.ref as match_ref,
row_number() over (partition by m.ref order by t2.ref) as alt_ref
from t2 left join
matches m
on t2.ref = m.ref
)
select tt1.name, tt2.name
from tt1 left join
tt2
on tt1.match_ref = tt2.match_ref or
(tt1.match_ref is null and tt2.match_ref is null and tt1.alt_ref = tt2.alt_ref);
Here is the idea. For each row in both tables, add two new columns:
match_ref is ref when ref exists in the other table.
alt_ref is an enumerated column for the ref values that do not match.
Once you have these columns, it is possible to join the tables together, by first checking match_ref and then -- if that is not present -- checking alt.ref.
SQL Fiddle does not appear to be working for SQL Server. However, here is an identical Postgres version that does work. Here is a working version using SQL Server (this is identical to the Postgres version).
A look at your Question
Correct me if I am wrong, but you have two tables that have an reference ID column of names that you wish to return results sets....only, you do not say distinct so you might end up with extras.
...some kind of full outer join, on column ref, that will not
produce NULL value until there is not any record..
The priority of the JOIN is with the values that have same ref, and if row count of tables are
not equal, there are some NULL results
Actually, the result is not really deterministic. Anyways, this question is still too vague. However, I think you really just want rows matching columns to appear together and anything not....well, not. But return everything.
So, if you know which side is larger, try this:
WITH C AS (SELECT DENSE_RANK() OVER (PARTITION BY ref ORDER BY NAME DESC) AS ROW_ID
, ref
, Name AS Name1
FROM T1)
SELECT Name1, B.Name2
FROM C
LEFT OUTER JOIN (SELECT DENSE_RANK() (OVER PARTITION BY ref ORDER BY NAME DESC) AS ROW_ID
, ref
, Name AS Name2) B ON B.Row_ID = C.Row_ID AND B.ref = C.ref
Each of the ref columns have a distinct ID to attach with. It is done in consecutive order, so if there is still an issue, well, you can figure that logic out. But I'm sure this will help you tremendously get where you are wanting. :)
Thank you every body and excuse me if I speak badly sometimes, count it on my fatigue because of hours working.
I think I couldn't say my meaning correctly, so I answered my own question. this is not the best answer and it is not optimized, I know, but it works!
SELECT t.ref,
t.NAME AS n1,
t2.NAME AS n2
INTO #tbl1
FROM #T1 AS t
LEFT JOIN #T2 AS t2
ON t2.ref = t.ref
WHERE t2.ref IS NOT NULL
SELECT ROW_NUMBER() OVER(ORDER BY t.NAME) AS rn,
*
INTO #tbl2
FROM #T1 AS t
WHERE t.ref NOT IN (SELECT ref
FROM #tbl1)
SELECT ROW_NUMBER() OVER(ORDER BY t.NAME) AS rn,
*
INTO #tbl3
FROM #T2 AS t
WHERE t.ref NOT IN (SELECT ref
FROM #tbl1)
SELECT n1,
n2
FROM #tbl1
UNION
SELECT t1.NAME AS n1,
t2.NAME AS n2
FROM #tbl2 t1
FULL OUTER JOIN #tbl3 t2
ON t1.rn = t2.rn
is there a way in SQL while we join two tables table_A and table_B, if we can’t match the two tables on a criteria said criteria_X at all we will try the second criteria criteria_Y
Something like this:
select *
from table_A, table_B
where table_A.id = table_B.id2
and (if there is no row where table_B.criteria_X = X then try table_B.criteria_Y = Y)
The following query is not a solution:
..
and (table_B.criteria_X = X OR table_B.criteria_Y = Y)
Thanks
This is a find the best match query:
select *
from
(
select *,
row_number() -- based on priority, #1 criteria_X, #2 criteria_Y
over (partition by table_A.id
order by case when table_B.criteria_X = X then 1
else 2
end) as best_match
from table_A, table_B
where table_A.id = table_B.id2
and (table_B.criteria_X = X OR table_B.criteria_Y = Y)
) dt
where best_match = 1
If the ORed condition results in loosing indexed access you might try splitting it into two UNION ALL selects.
A typical method uses left join twice . . . once for each criterion. Then then uses coalesce() in the select. And, with indexes on the join keys, this also should have very good performance:
select a.*, coalesce(b1.colx, b2.colx)
from table_A a left join
table_B b1
on a.id = b1.id2 and b1.criteria_X = X left join
table_B b2
on a.id = b1.id2 and b2.criteria_Y = Y
where b1.id2 is not null or b2.id2 is not null;
The where clause ensures that at least one row matches.
This does not work under all circumstances -- in particular, each join needs to return only 0 or 1 matching rows. This is often the situation with this type of "priority" joins.
An alternative version uses row_number(). This is sort of similar to #dnoeth's approach, but the row number calculation is done before the join:
select a.*, coalesce(b1.colx, b2.colx)
from table_A a join
(select b.*,
row_number() over (partition by id2
order by (case when criteria_x = X then 1
when criteria_y = Y then 2
end)
) as seqnum
from table_B b
where criteria_x = X or criteria_y = Y
) b
on a.id = b.id2 and seqnum = 1
What I want to do is to transform the following sql
SELECT X
FROM Y LEFT JOIN Z ON Y.Id=Z.id
WHERE Y.Fld='P'
into
SELECT Y
FROM Y LEFT JOIN (SELECT TOP 1 Id FROM Z WHERE Z.Id=Y.Id ORDER BY Z.PrimaryKey DESC) ON 1=1
WHERE Y.Fld='P'
The reason I want to do this is because Z has multiple rows that can be joined to Y, that are not unique in a distinguishable way, other than that the one we need is the latest one, and we only need that one record. Is this possible? I tried it but mssql complained that I cannot reference Y.Id from within the sub query.
How about a CTE approach:
;WITH CTE
AS
(
SELECT Id,
PrimaryKey,
ROW_NUMBER() OVER (PARTITION BY Id, ORDER BY Primarykey Desc) AS RN
FROM Z
)
SELECT X
FROM Y
LEFT JOIN CTE
ON CTE.ID = Y.ID
WHERE CTE.RN = 1
I want to optimze the follwing query, to not use subquery to get max value:
select c.ida2a2 from table1 m, table2 c
where c.ida3a5 = m.ida2a2
and (c.createstampa2 < (select max(cc.createstampa2)
from table2 cc where cc.ida3a5 = c.ida3a5));
Any idea? Please let me know if you want to get more info.
This may be a more efficient way to write the query:
select c.ida2a2
from table1 m join
(select c.*, MAX(createstampa2) over (partition by ida3a5) as maxcs
from table2 c
) c
on c.ida3a5 = m.ida2a2
where c.createstampa2 < maxcs
I'm pretty sure Oracle optimizes this correctly (filtering the rows before the join). If you wanted to be clearer:
select c.ida2a2
from table1 m join
(select c.*
from (select c.*, MAX(createstampa2) over (partition by ida3a5) as maxcs
from table2 c
) c
where c.createstamp2 < c.maxcs
) c
on c.ida3a5 = m.ida2a2