Update From Select with Correlated Subquery and Join in PostgreSQL - sql

I am migrating from SQL Server to Postgres and it has gone okay for the most part. One of the issues is that I am unable to figure out how to make this query work in Postgres:
update
"Measure"
set
DefaultStrataId = StrataId
FROM (SELECT "Strata"."MeasureId",
Min("Strata"."index") AS "Index"
FROM "Strata",
"Measure"
WHERE "Strata"."MeasureId" = "Measure"."MeasureId" and "Strata"."StrataId" in (select strataid from point)
GROUP BY "Strata"."MeasureId") a
INNER JOIN strata
ON "Strata"."index" = a."index"
where "Strata"."MeasureId" = "Measure"."MeasureId";
It complains: SQL Error [42601]: ERROR: syntax error at or near "FROM"
How do I get this to work?

You can use a DISTINCT ON for this to simplify it.
The ORDER BY in the sub-query will make sure that it's the "StrataId" for the minimum "index".
UPDATE "Measure" m
SET "DefaultStrataId" = q."StrataId"
FROM
(
SELECT DISTINCT ON (s."MeasureId") s."MeasureId", s."index", s."StrataId"
FROM "Strata" s
JOIN "Point" p ON p."StrataId" = s."StrataId"
JOIN "Measure" m ON m."MeasureId" = s."MeasureId"
ORDER BY s."MeasureId", s."index"
) q
WHERE q."MeasureId" = m."MeasureId";
Test on db<>fiddle here
Btw, the query below also works with the test data in that fiddle.
Basically, in Postgresql quoting a name isn't the same as not quoting a name.
MS Sql Server is much more tolerant in that aspect.
UPDATE "Measure"
SET "DefaultStrataId" = "StrataId"
FROM (SELECT "Strata"."MeasureId",
Min("Strata"."index") AS "index"
FROM "Strata",
"Measure"
WHERE "Strata"."MeasureId" = "Measure"."MeasureId" and "Strata"."StrataId" in (select "StrataId" from "Point")
GROUP BY "Strata"."MeasureId") a
INNER JOIN "Strata"
ON "Strata"."index" = a."index"
where "Strata"."MeasureId" = "Measure"."MeasureId";

Funky. After feeling shamed by #wildplasser to make my query non-disgusting, everything magically started working. It's not like I changed anything except switching to standard joins and adding aliases:
update
"Measure" m set
"DefaultStrataId" = "StrataId"
from
(
select
s."MeasureId",
min(s."Index") as "Index"
from
"Measure" m
inner join "Strata" s on
s."MeasureId" = m."MeasureId"
where s."StrataId" in (
select
s."StrataId"
from
"Point")
group by
s."MeasureId") a
inner join "Strata" s on
s."Index" = a."Index"
where
s."MeasureId" = m."MeasureId";

Your only goal appears to be getting the minimal value from Strata
Omitting all the ugly quotes,and adding some aliasses (assuming that only one record with the minumum value exists) :
UPDATE Measure m
SET DefaultStrataId = s.StrataId
FROM Strata s
WHERE s.MeasureId = m.MeasureId
AND NOT EXISTS (
SELECT * FROM Strata nx
where nx.MeasureId = s.MeasureId
AND nx."index" < s."index"
)
;

Related

How to use NOT EXISTS and JOIN at the same time?

We are required to display UID that is in BOS_BARCODE_IT_LOG but not exists in BOS_BARCODE_DO_LOG
The reason that I joined with OITM is because the user asked for the selection Criteria in SAP Business One.
SELECT X0."DATE",X0."ITEMCODE", X0."UID"
FROM "BOS_BARCODE_IT_LOG" X0 JOIN OITM X1 ON
X0."ITEMCODE" = X1."ItemCode"
WHERE
X1."ItemCode" = '[%0]'
AND NOT EXISTS (
SELECT X2."UID" FROM "BOS_BARCODE_DO_LOG" X2
WHERE X0."ITEMCODE" = X2."ITEMCODE" AND
X0."UID" = X2."UID" AND
X0."DATE" = X2."DATE"
)
We need that '[%0]' in order to display
The problem is that, when I tried to search any items there, the query returns no result.
What I've tried.
I Select only from one table without OITM, and neverthless, did not provide Query Selection Criteria.
I Tried this as well
SELECT X0."DATE",X0."ITEMCODE", X0."UID"
FROM "BOS_BARCODE_IT_LOG" X0
WHERE
X0."ITEMCODE" = '[%0]' AND
NOT EXISTS (
SELECT X1."UID" FROM "BOS_BARCODE_DO_LOG" X1
WHERE X0."ITEMCODE" = X1."ITEMCODE" AND
X0."UID" = X1."UID" AND
X0."DATE" = X1."DATE"
)
And it provide error.
1). [SAP AG][LIBODBCHDB DLL][HDBODBC] Syntax error or access violation;257 sql syntax error: incorrect syntax near ")": line 14 col 1 'Received Alerts' (OAIB) (at pos 299)
Another thing, is it possible to use subquery with more than one tables and provide the expected result (Not just blank result)
What I learned in the tutorial that subquery only used for one table.
This is one of the examples.
https://www.tutorialspoint.com/sql/sql-sub-queries.htm
Thanks.
We are required to display UID that is in BOS_BARCODE_IT_LOG but not exists in BOS_BARCODE_DO_LOG.
I don't undersand how your queries actually relate to the question (they have one additional table oitm, and many more columns). From the description of your question it seems like you want:
select bi.uid
from bos_barcode_it_log bi
where not exists (select 1 from bos_barcode_do_log bd where bd.uid = bi.uid)
If you need oitm for filtering, you can join (if there is not more than one row in per itemcode in oitm), or use exists:
select bi.uid
from bos_barcode_it_log bi
where
exists (select 1 from oitm o where o.itemcode = bi.itemcode)
and not exists (select 1 from bos_barcode_do_log bd where bd.uid = bi.uid)

Getting ambiguity error for a inventory SQL query where two fields should be equal to make the calculation. MS-ACCESS

Having this simple group of tables, I would like to make an inventory discriminating equal products that came from different providers, but I'm getting an "ambiguity error" running a query I though it would work. I don't know how to solve this.
Here's the query I tried:
SELECT tblProducts.product_Name,
tblProviders.provider,
Nz(Sum(tblIntakes.intake_QTY),0)-
Nz(Sum(tblExits.exit_QTY)) AS Stock
FROM tblProviders,
(tblProducts LEFT JOIN
tblExits
ON tblProducts.product_ID = tblExits.product_ID
) LEFT JOIN
tblIntakes
ON tblProducts.product_ID = tblIntakes.product_ID
GROUP BY tblProducts.product_Name, tblProviders.provider;
You may use subqueries in this case:
SELECT
tblProducts.product_Name,
tblProviders.provider,
Nz((
SELECT SUM(intake_QTY)
FROM tblIntakes
WHERE
tblIntakes.product_ID = tblProducts.product_ID AND
tblIntakes.provider_ID = tblProviders.provider_ID
), 0) -
Nz((
SELECT SUM(exit_QTY)
FROM tblExits
WHERE
tblExits.product_ID = tblProducts.product_ID AND
tblExits.provider_ID = tblProviders.provider_ID
), 0) AS Stock
FROM tblProviders, tblProducts;

DISTINCT SQL query with inner joins that omits a column from considerations,

I have a DB2 query as follows:
SELECT DISTINCT RETAILMASTERFILE.DOIDCD AS "RETAILMASTERFILE_DOIDCD",
RETAILMASTERFILE.COCOMO AS "RETAILMASTERFILE_COCOMO",
#XENOS.CUSTREF AS "XENOS_CUSTREF",
#XENOS.ADDUDT AS "XENOS_ADDUDT",
#XENOS.ADUPDD AS "XENOS_ADUPDD",
#XENOS.ADUPDT AS "XENOS_ADUPDT",
#XENOS.ADSTAT AS "XENOS_ADSTAT"
FROM RETAILMASTERFILE INNER JOIN
#XENOS ON RETAILMASTERFILE.DOCOMP = #XENOS.ADCOMP
AND RETAILMASTERFILE.COCOMO = #XENOS.ADDELN
WHERE (RETAILMASTERFILE.DOIDCD = 'CUST008')
AND (RETAILMASTERFILE.COCOMO = '345126032')
AND (RETAILMASTERFILE.DOCOMP = 'LONDON')
The problem is #XENOS.ADUPDT may not be unique which gives me an unwanted duplicate record.
Is there any way I can exclude this from consideration ? Everything I've tried so far within my limited knowledge and crude understanding of group by has so far broken my query.
Use GROUP BY instead:
SELECT RETAILMASTERFILE.DOIDCD AS "RETAILMASTERFILE_DOIDCD",
RETAILMASTERFILE.COCOMO AS "RETAILMASTERFILE_COCOMO",
#XENOS.CUSTREF AS "XENOS_CUSTREF",
#XENOS.ADDUDT AS "XENOS_ADDUDT",
#XENOS.ADUPDD AS "XENOS_ADUPDD",
MAX(#XENOS.ADUPDT) AS "XENOS_ADUPDT",
#XENOS.ADSTAT AS "XENOS_ADSTAT"
FROM RETAILMASTERFILE INNER JOIN
#XENOS
ON RETAILMASTERFILE.DOCOMP = #XENOS.ADCOMP AND
RETAILMASTERFILE.COCOMO = #XENOS.ADDELN
WHERE (RETAILMASTERFILE.DOIDCD = 'CUST008') AND (RETAILMASTERFILE.COCOMO = '345126032') AND
(RETAILMASTERFILE.DOCOMP = 'LONDON')
GROUP BY RETAILMASTERFILE.DOIDCD,
RETAILMASTERFILE.COCOMO,
#XENOS.CUSTREF,
#XENOS.ADDUDT,
#XENOS.ADUPDD,
#XENOS.ADSTAT;

SQL query for filtering data

I`m working on some sql queries to get some data out of a table; I have made 2 queries for the
same data but both give another result. The 2 queries are:
SELECT Samples.Sample,
data_overview.Sample_Name,
data_overview.Sample_Group,
data_overview.NorTum,
data_overview.Sample_Plate,
data_overview.Sentrix_ID,
data_overview.Sentrix_Position,
data_overview.HybNR,
data_overview.Pool_ID
FROM tissue INNER JOIN (
( patient INNER JOIN data_overview
ON patient.Sample = data_overview.Sample)
INNER JOIN Samples ON
(data_overview.Sample_id = Samples.Sample_id) AND
(patient.Sample = Samples.Sample)
) ON
(tissue.Sample_Name = data_overview.Sample_Name) AND
(tissue.Sample_Name = patient.Sample_Name)
WHERE data_overview.Sentrix_ID= 1416198
OR data_overview.Pool_ID='GS0005701-OPA'
OR data_overview.Pool_ID='GS0005702-OPA'
OR data_overview.Pool_ID='GS0005703-OPA'
OR data_overview.Pool_ID='GS0005704-OPA'
OR data_overview.Sentrix_ID= 1280307
ORDER BY Samples.Sample;")
And the other is
SELECT Samples.Sample,
data_overview.Sample_Name,
data_overview.Sample_Group,
data_overview.NorTum,
data_overview.Sample_Plate,
data_overview.Sentrix_ID,
data_overview.Sentrix_Position,
data_overview.HybNR,
data_overview.Pool_ID
FROM tissue INNER JOIN
(
(patient INNER JOIN data_overview
ON patient.Sample = data_overview.Sample)
INNER JOIN Samples ON
(data_overview.Sample_id = Samples.Sample_id)
AND (patient.Sample = Samples.Sample)) ON
(tissue.Sample_Name = data_overview.Sample_Name)
AND (tissue.Sample_Name = patient.Sample_Name)
WHERE ((
(data_overview.Sentrix_ID)=1280307)
AND (
(data_overview.Pool_ID)="GS0005701-OPA"
OR (data_overview.Pool_ID)="GS0005702-OPA"
OR (data_overview.Pool_ID)="GS0005703-OPA"
OR (data_overview.Pool_ID)="GS0005704-OPA"))
OR (((data_overview.Sentrix_ID)=1416198))
ORDER BY data_overview.Sample;
The one in the top is working quite well but it still won't filter the sentrix_ID.
The second 1 is created with Access but when I try to run this Query in R it gave
a unexpected symbol error. So if anyone knows how to create a query that filter POOL_ID and Sentrix_id with the given parameters thanks in advance
Is it a case of making the where clause something like this:
WHERE Sentrix_ID = 1280307 AND (Pool_ID = 'VAL1' OR Pool_ID = 'VAL2' OR Pool_ID = 'VAL3')
i.e. making sure you have brackets around the "OR" components?
Maybe you meant:
...
WHERE data_overview.Sentrix_ID IN (1280307,1416198 )
AND data_overview.Pool_ID IN ("GS0005701-OPA", "GS0005702-OPA", "GS0005703-OPA" ,"GS0005704-OPA")
;

Problem with adding custom sql to finder condition

I am trying to add the following custom sql to a finder condition and there is something not quite right.. I am not an sql expert but had this worked out with a friend who is..(yet they are not familiar with rubyonrails or activerecord or finder)
status_search = "select p.*
from policies p
where exists
(select 0 from status_changes sc
where sc.policy_id = p.id
and sc.status_id = '"+search[:status_id].to_s+"'
and sc.created_at between "+status_date_start.to_s+" and "+status_date_end.to_s+")
or exists
(select 0 from status_changes sc
where sc.created_at =
(select max(sc2.created_at)
from status_changes sc2
where sc2.policy_id = p.id
and sc2.created_at < "+status_date_start.to_s+")
and sc.status_id = '"+search[:status_id].to_s+"'
and sc.policy_id = p.id)" unless search[:status_id].blank?
My find statement:
Policy.find(:all,:include=>[{:client=>[:agent,:source_id,:source_code]},{:status_changes=>:status}],
:conditions=>[status_search])
and I am getting this error message in my log:
ActiveRecord::StatementInvalid (Mysql::Error: Operand should contain 1 column(s): SELECT DISTINCT `policies`.id FROM `policies` LEFT OUTER JOIN `clients` ON `clients`.id = `policies`.client_id WHERE ((((policies.created_at BETWEEN '2009-01-01' AND '2009-03-10' OR policies.created_at = '2009-01-01' OR policies.created_at = '2009-03-10')))) AND (select p.*
from policies p
where exists
(select 0 from status_changes sc
where sc.policy_id = p.id
and sc.status_id = '2'
and sc.created_at between 2009-03-10 and 2009-03-10)
or exists
(select 0 from status_changes sc
where sc.created_at =
(select max(sc2.created_at)
from status_changes sc2
where sc2.policy_id = p.id
and sc2.created_at < 2009-03-10)
and sc.status_id = '2'
and sc.policy_id = p.id)) ORDER BY clients.created_at DESC LIMIT 0, 25):
what is the major malfunction here - why is it complaining about the columns?
The conditions modifier is expecting a condition (e.g. a boolean expression that could go in a where clause) and you are passing it an entire query (a select statement).
It looks as if you are trying to do too much in one go here, and should break it down into smaller steps. A few suggestions:
use the query with find_by_sql and don't mess with the conditions.
use the rails finders and filter the records in the rails code
Also, note that constructing a query this way isn't secure if the values like status_date_start can come from users. Look up "sql injection attacks" to see what the problem is, and read the rails documentation & examples for find_by_sql to see how to avoid them.
Ok, I've managed to retool this so it is more friendly to a conditions modifier and I think it is doing the sql query correctly.. however, it is returning policies that when I try to list the current status (the policy.status_change.last.status) it is set to the same status used in the query - which is not correct
here is my updated condition string..
status_search = "status_changes.created_at between ? and ? and status_changes.status_id = ?) or
(status_changes.created_at = (SELECT MAX(sc2.created_at) FROM status_changes sc2
WHERE sc2.policy_id = policies.id and sc2.created_at < ?) and status_changes.status_id = ?"
is there something obvious to this that is not returning all of the remaining associated status changes once it finds the one in the query?
here is the updated find..
Policy.find(:all,:include=>[{:client=>[:agent,:source_id,:source_code]},:status_changes],
:conditions=>[status_search,status_date_start,status_date_end,search[:status_id].to_s,status_date_start,search[:status_id].to_s])