Creating two distinct columns using WHERE clause from the same main table - oracle-sqldeveloper

I need to pull two columns (B and C) from the same column (A) from Table_2. These two columns (script below) are implemented into a larger query. When I run the query with only one of the columns, for instance only B, then the query runs well and in just a few seconds. However, when I run both B and C within the query at the same time, the query just keeps running and does not end. I have tried giving the two columns different aliases to see if that would solve the problem, but I have not been able to figure out why the query does not run with both B and C present. The two columns are almost the same apart from the WHERE clause.
I only have one join in the script for both B and C columns similar to: FROM Table_1 T1, Table_2 T2 WHERE T2.ENT_REF = T1.ENT_REF (+)
Any ideas?
( SELECT
SUM(T2.A) as prem
FROM Table_2 T2
WHERE T2.ENT_REF = T1.ENT_REF
AND UPPER(T2.PER) = 'HURR'
AND UPPER(T2.ENT_TYPE) = 'POL'
AND T2.Cov NOT IN ('OUTPROP','COV')
) B,
(SELECT
SUM(T2.A) as prem
FROM Table_2 T2
WHERE T2.ENT_REFE = T1.ENT_REF
AND UPPER(T2.PER) IN ('I', 'II', 'II')
AND UPPER(T2.ENT_TYPE) = 'POL'
AND T2.Cov NOT IN ('OUTPROP','COV')
) C

You need the dummy table in PL/SQL. (From dual)
You also need to join the table (table_1).
Please make sure that every single query can return your expected value.
In your original queries, you put 'T2.ENT_REF = T1.ENT_REF' but you did not add the table_1. This will cause the syntax error.
Please try this:
SELECT
(SELECT
SUM(T2.A) as prem
FROM Table_2 T2, Table_2 T1
WHERE T2.ENT_REF = T1.ENT_REF
AND UPPER(T2.PER) = 'HURR'
AND UPPER(T2.ENT_TYPE) = 'POL'
AND T2.Cov NOT IN ('OUTPROP','COV')
) as B,
(SELECT
SUM(T2.A) as prem
FROM Table_2 T2, Table_2 T1
WHERE T2.ENT_REFE = T1.ENT_REF
AND UPPER(T2.PER) IN ('I', 'II', 'II')
AND UPPER(T2.ENT_TYPE) = 'POL'
AND T2.Cov NOT IN ('OUTPROP','COV')
) as C
FROM DUAL
Update:
You can use [concat]
SELECT
CONCAT(
(SELECT
SUM(T2.A) as prem
FROM Table_2 T2, Table_2 T1
WHERE T2.ENT_REF = T1.ENT_REF
AND UPPER(T2.PER) = 'HURR'
AND UPPER(T2.ENT_TYPE) = 'POL'
AND T2.Cov NOT IN ('OUTPROP','COV')
) ,
(SELECT
SUM(T2.A) as prem
FROM Table_2 T2, Table_2 T1
WHERE T2.ENT_REFE = T1.ENT_REF
AND UPPER(T2.PER) IN ('I', 'II', 'II')
AND UPPER(T2.ENT_TYPE) = 'POL'
AND T2.Cov NOT IN ('OUTPROP','COV')
)
) AS BandC
FROM DUAL
Update 2:
SELECT
(
(SELECT
SUM(T2.A) as prem
FROM Table_2 T2, Table_2 T1
WHERE T2.ENT_REF = T1.ENT_REF
AND UPPER(T2.PER) = 'HURR'
AND UPPER(T2.ENT_TYPE) = 'POL'
AND T2.Cov NOT IN ('OUTPROP','COV')
) +
(SELECT
SUM(T2.A) as prem
FROM Table_2 T2, Table_2 T1
WHERE T2.ENT_REFE = T1.ENT_REF
AND UPPER(T2.PER) IN ('I', 'II', 'II')
AND UPPER(T2.ENT_TYPE) = 'POL'
AND T2.Cov NOT IN ('OUTPROP','COV')
)
) AS BandC
FROM DUAL

Related

N1QL query dropping records after join with a subquery

The Below Query is dropping records when i join 2 N1QL sub queries -
We are using couchbase and using N1QL queries.
Full Query -
select
t3.appName,
t3.uuid_proj as uuid,
t3.description,
t3.env,
t3.productStatus
from
( select
t1.uuid as uuid_proj ,
t1.appName as appName ,
t1.description as description,
t2.env as env,
t2.productStatus as productStatus
from
(
select
api_external.uuid ,
api_external.data.appName ,
api_external.data.description
from `api_external`
where type = 'partnerApp'
and data.companyId = '70a149da27cc425da86cba890bf5b143' )t1
join
(
select
api_external.data.env,
api_external.data.productStatus,
api_external.data.partnerAppId
from
`api_external`
where type = 'integration' )t2
on t1.uuid = t2.partnerAppId
) as t3
join (
select t4.uuid as uuid_agg , min(t5.env) as env
from
(select api_external.uuid from `api_external` where type = 'partnerApp' and data.companyId = '70a149da27cc425da86cba890bf5b143' )as t4 join
(select api_external.data.env, api_external.data.partnerAppId from `api_external` where type = 'integration' ) as t5
on t4.uuid = t5.partnerAppId
group by t4.uuid
) as t6
on
t3.uuid_proj = t6.uuid_agg and t3.env = t6.env
As you see it has 2 sub queries -
The below subquery gives 16 records -
select
t1.uuid as uuid_proj
from
(
select
api_external.uuid ,
api_external.data.appName ,
api_external.data.description
from `api_external`
where type = 'partnerApp'
and data.companyId = '70a149da27cc425da86cba890bf5b143' )t1
join
(
select
api_external.data.env,
api_external.data.productStatus,
api_external.data.partnerAppId
from
`api_external`
where type = 'integration' )t2
on t1.uuid = t2.partnerAppId
group by t1.uuid
Also the other subquery also gives 16 records -
select t4.uuid as uuid_agg , min(t5.env) as env
from
(select api_external.uuid from `api_external` where type = 'partnerApp' and data.companyId = '70a149da27cc425da86cba890bf5b143' )as t4 join
(select api_external.data.env, api_external.data.partnerAppId from `api_external` where type = 'integration' ) as t5
on t4.uuid = t5.partnerAppId
group by t4.uuid
By Logic join of both the queries on the same grain UUID must also give 16 records . But it gives only 1 .
What am i doing wrong Please help
The query uses many subqueries and hit the issue.
Try following simplified version
CREATE INDEX ix1 ON api_external(data.companyId, uuid, data.appName, data.description) WHERE type = "partnerApp";
CREATE INDEX ix2 ON api_external(data.partnerAppId, data.env, data.productStatus) WHERE type = "integration";
WITH ct3 AS (SELECT t1.uuid, t1.data.appName, t1.data.description,
t2.data.env, t2.data.productStatus
FROM api_external AS t1
JOIN api_external AS t2 ON t1.uuid = t2.data.partnerAppId
WHERE t1.type = "partnerApp"
AND t1.data.companyId = "70a149da27cc425da86cba890bf5b143"
AND t2.type = "integration"
AND t2.data.partnerAppId IS NOT NULL),
ct6 AS ( SELECT t4.uuid AS uuid_agg , MIN(t5.data.env) AS env
FROM api_external AS t4
JOIN api_external AS t5 ON t4.uuid = t5.data.partnerAppId
WHERE t4.type = "partnerApp"
AND t4.data.companyId = "70a149da27cc425da86cba890bf5b143"
AND t5.type = "integration"
AND t5.data.partnerAppId IS NOT NULL
GROUP BY t4.uuid)
SELECT t3.*
FROM ct3 AS t3
JOIN ct6 AS t6 ON t3.uuid = t6.uuid_agg and t3.env = t6.env;
If same results see following works . After JOIN get all the fields of results of MIN env record each group
SELECT m[1].*
FROM api_external AS t4
JOIN api_external AS t5 ON t4.uuid = t5.data.partnerAppId
WHERE t4.type = "partnerApp"
AND t4.data.companyId = '70a149da27cc425da86cba890bf5b143'
AND t5.type = "integration"
AND t5.data.partnerAppId IS NOT NULL
GROUP BY t4.uuid
LETTING m = MIN([t5.data.env, {t4.uuid, t4.data.appName, t4.data.description,
t5.data.env, t5.data.productStatus}]);

Syntax Error: Lateral Join with Delete (PostgreSQL)

PostgreSQL 11.1
AFAIK, this is correct and should run. It Fails with syntax error on Delete. What am I missing?
Thanks for any help.
ERROR: syntax error at or near "DELETE"
LINE 41: DELETE FROM d
WITH _in (tservice, patient_recid, disease_recid, new_disease_recid) AS (
VALUES ('2021-04-21'::timestamp, '23262'::integer, '34978'::integer, '33364'::integer)
)
UPDATE dx d
SET disease_recid = n.new_disease_recid
FROM _in n,
LATERAL ( WITH RECURSIVE readtoend AS(
SELECT recid, newrecid
FROM patients p1
JOIN _in n ON p1.recid = n.patient_recid
UNION
SELECT c.recid, c.newrecid
FROM patients c
INNER JOIN readtoend s ON s.newrecid = c.recid
),
readtostart AS(
SELECT recid, newrecid
FROM patients p1
JOIN _in n ON p1.recid = n.patient_recid
UNION
SELECT c.recid, c.newrecid
FROM patients c
INNER JOIN readtostart s ON s.recid = c.newrecid
)
SELECT recid FROM readtoend
UNION
SELECT recid FROM readtostart
) j,
LATERAL ( WITH _get_existing_target AS(
SELECT d.*
FROM d
WHERE (d.patient_recid, d.disease_recid) = (j.recid, n.new_disease_recid) AND d.tservice <= n.tservice
),
_get_conflicts AS(
SELECT d.*
FROM d
WHERE (d.patient_recid, d.disease_recid) = (j.recid, n.disease_recid) AND EXISTS ( SELECT 1
FROM _get_existing_target x
WHERE d.patient_recid = x.patient_recid AND d.tservice::date = x.tservice::date)
)
DELETE FROM d
USING _get_conflicts f
WHERE d.recid = f.recid
RETURNING d.*
) del
WHERE (d.patient_recid, d.disease_recid) = (j.recid, n.disease_recid) AND d.tservice::date <= n.tservice::date
AND d.recid NOT IN ( SELECT recid FROM del);
You cannot use DELETE ... RETURNING in the FROM list of a query.

PostgreSQL pass value into INNER JOIN

PostgreSQL 11
How to pass o.create_date value into INNER JOIN? I need Max ID before o.create_date
SELECT o.id,
o.create_date date,
sum(oi.quantity) qty,
sum(oi.quantity * sp.price) total
FROM ax_order o
LEFT JOIN ax_order_invenotry oi on o.id = oi.order_id
LEFT JOIN ax_inventory i on i.id = oi.inventory_id
LEFT JOIN ax_suppliers s on s.id = o.supplier_id
INNER JOIN ax_supplier_price sp ON (sp.inventory_id = oi.inventory_id and sp.supplier_id = o.supplier_id)
INNER JOIN
(
SELECT inventory_id,
max(id) id
FROM ax_supplier_price
WHERE create_date <= o.create_date
GROUP BY inventory_id
) lsp ON (sp.id = lsp.id)
WHERE o.store_id = 13
AND o.supplier_id = 35
GROUP BY o.id, o.create_date
ORDER BY o.id
You could use the LATERAL join mechanism to make it work:
WITH ax_order AS (
SELECT *
FROM (VALUES (1, '2000-1-1'::date, 1, 1)) as x(id, create_date, store_id, supplier_id)
), ax_order_inventory AS (
SELECT *
FROM (VALUES (1, 2, 4)) as x(order_id, inventory_id, quantity)
), ax_supplier_price AS (
SELECT *
FROM (VALUES (1, 2, 1, 10, '1999-12-31'::date)) as x(id, inventory_id, supplier_id, price, create_date)
)
SELECT o.id,
o.create_date date,
sum(oi.quantity) qty,
sum(oi.quantity * sp.price) total
FROM ax_order o
LEFT JOIN ax_order_inventory oi on o.id = oi.order_id
INNER JOIN ax_supplier_price sp ON (sp.inventory_id = oi.inventory_id and sp.supplier_id = o.supplier_id)
INNER JOIN LATERAL
(
SELECT inventory_id,
max(lsp.id) id
FROM ax_supplier_price lsp
WHERE sp.create_date <= o.create_date
GROUP BY inventory_id
) lsp ON sp.id = lsp.id
GROUP BY o.id, o.create_date
ORDER BY o.id
I deleted some JOINs that were not strictly necessary and mocked your data as well as I could see. Note, however, that you could also use a WHERE clause to find it - which should be more efficient:
WITH ax_order AS (
SELECT *
FROM (VALUES (1, '2000-1-1'::date, 1, 1)) as x(id, create_date, store_id, supplier_id)
),
ax_order_inventory AS (
SELECT *
FROM (VALUES (1, 2, 4)) as x(order_id, inventory_id, quantity)
),
ax_supplier_price AS (
SELECT *
FROM (VALUES (1, 2, 1, 10, '1999-12-31'::date)) as x(id, inventory_id, supplier_id, price, create_date)
)
SELECT o.id,
o.create_date date,
sum(oi.quantity) qty,
sum(oi.quantity * sp.price) total
FROM ax_order o
LEFT JOIN ax_order_inventory oi on o.id = oi.order_id
INNER JOIN ax_supplier_price sp
ON (sp.inventory_id = oi.inventory_id and sp.supplier_id = o.supplier_id)
WHERE sp.id =
(
-- NOTE: no GROUP BY necessary!
SELECT max(lsp.id) id
FROM ax_supplier_price lsp
WHERE sp.create_date <= o.create_date
AND lsp.inventory_id = sp.inventory_id
)
GROUP BY o.id, o.create_date
ORDER BY o.id

Is there a way to merge these json aggregations?

I am trying to create json object from getting some info from one table, then creating interger arrays from some other tables' id's and adding n > 1 (2 or more) arrays to the json object. I am using Postgres version 10.7:
select json_build_object(
'id', bi.id,
'street', ba.street,
'features1', features1.f1_json_arr,
'features2', features2.f2_json_arr
)
from business.info bi
inner join business.address ba on bi.id = ba.location_id
left outer join (
select f1.location_id,
json_agg(f1_id) as f1_json_arr
from business.features1 as f1
group by f1.location_id
) features1 on bi.id = features1.location_id
left outer join (
select f2.location_id,
json_agg(f2_id) as f2_json_arr
from business.feature2 as f2
group by f2.location_id
) features2 on bi.id = features2.location_id
where bi.id='1234';
which gives me a result as I want, like so:
{
"id": "1234",
"street", "some street",
"features1": [
2,
1
],
"features2": [
3,
2,
1
]
}
Is there a cleaner way to do this? I tried this:
select json_build_object(
'id', bi.id,
'street', ba.street_name,
'features1', f1_and_f2.f1_json_arr,
'features2', f1_and_f2.f2_json_arr
)
from business.info bi
inner join business.address ba
on bi.id = ba.location_id
left outer join (
select f1.location_id,
json_agg(f1_id) as f1_json_arr,
json_agg(f2_id) as f2_json_arr
from business.feature1 as f1
inner join business.feature2 as f2 on f1.location_id = f2.location_id
group by f1.location_id
) f1_and_f2 on bi.id = f1_and_f2.location_id
where bi.id = '1234';
but got a result like this:
{
"id": "1234",
"street_name": "a street",
"features1": [
2,
2,
2,
1,
1,
1
],
"features2": [
3,
2,
1,
3,
2,
1
]
}
SELECT A.*, B.*, C_GROUPED.C_STUFF, D_GROUPED.D_STUFF
FROM A
INNER JOIN B ON B.A_ID = A.ID
LEFT JOIN ( SELECT A_ID, JSON_AGG(STUFF) AS C_STUFF FROM C GROUP BY A_ID ) AS C_GROUPED ON C_GROUPED.A_ID = A.ID
LEFT JOIN ( SELECT A_ID, JSON_AGG(OTHER_STUFF) AS D_STUFF FROM D GROUP BY A_ID ) AS D_GROUPED ON D_GROUPED.A_ID = A.ID
WHERE A.ID = 123;
should return the same result as
SELECT
A.*,
B.*,
( SELECT JSON_AGG(STUFF) FROM C WHERE C.A_ID = A.ID ) AS C_STUFF,
( SELECT JSON_AGG(OTHER_STUFF) FROM D WHERE D.A_ID = A.ID ) AS D_STUFF
FROM A
INNER JOIN B ON B.A_ID = A.ID
WHERE A.ID = 123
In fact, I would expect the second query be faster.
Ps - Since LEFT JOIN and LEFT OUTER JOIN are the same, I would suggest writing them in the same way in your query.

Faster left join with last non-empty

Table1:
Shop
Manager
Date
Table2:
Shop
Date
Sales
I need to get Table2 with Manager field from Table1. I did the following trick:
select
t1.[Shop]
,t1.[Date]
,t1.[Sum]
,t2.[Manager]
from t1
left join t2
on t1.[Shop] = t2.[Shop]
and t2.[Date] = (select max(t2.[Date]) from t2
where t2.[Shop] = t1.[Shop]
and t2.[Date] < t1.[Date])
It works, but subquerying is very slow, so I wonder if there is more elegant and fast way to do so?
Some sample data to play around: http://pastebin.com/uLN6x5JE
may seem like a round about way but join on a single condition is typically faster
select t12.[Shop], t12.[Date], t12.[Sum]
, t12.[Manager]
from
( select t1.[Shop], t1.[Date], t1.[Sum]
, t2.[Manager]
, row_number() over (partition by t2.[Shop] order by t2.[Date] desc) as rn
from t1
join t2
on t2.[Shop] = t1.[Shop]
and t1.[Date] < t1.[Date]
) as t12
where t12.rn = 1
union
select t1.[Shop], t1.[Date], t1.[Sum]
, null as [Manager]
from t1
left join t2
on t2.[Shop] = t1.[Shop]
and t1.[Date] < t1.[Date]
group by t1.[Shop], t1.[Date], t1.[Sum]
having count(*) = 1
You may get much better performance by adding a covering index on t2 if you don't already have one:
create index T2ShopDate on t2 ([Shop], [Date]) include ([Manager])
Here is a version that uses a CTE to find all maximum manager dates first and then join back to t2 to get the manager:
;with MaxDates ([Shop], [Date], [Sum], [MaxMgrDate]) as
(
select
t1.[Shop]
,t1.[Date]
,t1.[Sum]
,max(t2.[Date])
from t1
left join t2
on t2.[Shop] = t1.[Shop]
and t2.[Date] < t1.[Date]
group by
t1.[Shop]
,t1.[Date]
,t1.[Sum]
)
select
MaxDates.[Shop]
,MaxDates.[Date]
,MaxDates.[Sum]
,t2.[Manager]
from MaxDates
inner join t2
on t2.[Date] = MaxDates.[MaxMgrDate]
You might be able to remove the second join back to t2 by using row_number():
;with MaxDates ([Shop], [Date], [Sum], [Manager], [RowNum]) as
(
select
t1.[Shop]
,t1.[Date]
,t1.[Sum]
,t2.[Manager]
,row_number() over (partition by (t1.[Shop]) order by t2.[Date] desc)
from t1
left join t2
on t2.[Shop] = t1.[Shop]
and t2.[Date] < t1.[Date]
)
select *
from MaxDates
where RowNum = 1