How to use a column value in one of the select statement in the join in postgresql - postgresql

I'm updating sitename as below. But then I need to utilize the levelindex from a in another query which is getting joined with the first query.
update billofquantity_temp a
set sitename = b.boqitemname
from (
select a.* from
(
select levelindex,productno,boqitemid,boqitemname,fileid from billofquantity_temp
where productno ='' and levelindex !='' //first query
) a
join
(
select distinct substring(levelindex,1,length(a.levelindex) lblindex from billofquantity_temp
where boqitemid !='' and levelindex !=''
and length(levelindex) > 2
) b on a.levelindex=b.lblindex // second query
) b
where a.levelindex=b.levelindex;
I need to use the a.levelindex in second query to get the substrings of the it's length. But this throws error invalid reference to FROM-clause entry for table "a"
Is there any other way to use the column from query 1 in 2 while joining them?
Update:
Based on kims answer, I could get the selection done but there is error syntax error at c.a.levelindex. There error is thrown even with c.levelindex.
A slight modification to the query made no errors but the intened update doesn't happen. Instead only one particular values is updated. Below is the updated query to remove errors
update billofquantity_temp d
set sitename = c.boqitemname
from (
select * from (
select levelindex, boqitemname from billofquantity_temp
where productno = '' and levelindex != '' -- first query
) a
join (
select distinct levelindex lblindex from billofquantity_temp
where boqitemid != '' and levelindex != '' and length(levelindex) > 2 ) b
on a.levelindex = substring(b.lblindex, 1, length(a.levelindex)) -- second query
) c
where d.levelindex = c.lblindex;

Move the computation of lblindex outside the sub-select to the on clause:
update billofquantity_temp d
set sitename = c.boqitemname
from (
select *
from (
select levelindex, boqitemname
from billofquantity_temp
where productno = '' and levelindex != '' -- first query
) a
join (
select distinct levelindex
from billofquantity_temp
where boqitemid != '' and levelindex != '' and length(levelindex) > 2
) b
on a.levelindex = substring(b.levelindex, 1, length(a.levelindex)) -- second query
) c
where d.levelindex = c.a.levelindex
;
I've also used c and d to avoid confusion from using a and b twice, added a missing ), and removed unused fields from select.

Related

How to properly nest select queries in postgresql? A specific (somewhat complex) example

I'd like some help with a query that I'm trying to build.
I have the following query that I'm building:
select sd.address,
sd.colour_code,
s.id as deactivated_id,
s.type,
'http://site/groups/' || c.group_id || '/user/' || c.subject_id as URL
from sensors s
join contracts c on s.contract_id=c.id
join sensordevices sd on sd.id=s.device_id
where s.begin_time is not null and
s.end_time is not null and
c.end_date is null and
not exists (select * from sensors sb
where sb.begin_time is not null and --b properly entered
sb.end_time is null and -- b active
sb.contract_id=s.contract_id and
s.type=sb.type and
s.end_time<=sb.begin_time)
;
Which generates a table like this (without the barcode column which I would like to add):
On which I would like a barcode column, but the barcode is not in the database but a derived attribute.
In order to get barcodes I was given the following query:
SELECT
ean || '' ||
(
10
-
(
(
SELECT
SUM(digit)
FROM (
SELECT
ROW_NUMBER() over () AS pos,
digit
FROM (
SELECT
REGEXP_SPLIT_TO_TABLE(
ean::TEXT,
''::TEXT
)::INT AS digit
) AS split
) AS sub
WHERE pos < LENGTH(ean::TEXT)
AND pos % 2 = LENGTH(ean::TEXT) % 2
)
+
(
SELECT
SUM(digit * 3)
FROM (
SELECT
ROW_NUMBER() over () AS pos,
digit
FROM (
SELECT
REGEXP_SPLIT_TO_TABLE(
ean::TEXT,
''::TEXT
)::INT AS digit
) AS split
) AS sub
WHERE pos < LENGTH(ean::TEXT)
AND pos % 2 = (LENGTH(ean::TEXT) - 1) % 2
)
) % 10
) % 10 as barcode
FROM
(select '0' || sd.type || '00000' || sd.address as ean
from sensors s
join sensordevices sd on s.device_id = sd.id
) as ean;
Which returns a table with a single column, barcode.
So, my question is, how can I use the second query to select the barcode for the first statement?
What I tried was the following:
On my query after select I added brc.barcode and after from (SECOND-LARGE-QUERY-HERE) brc, but I got this error: [53100] ERROR: could not write to file "base/pgsql_tmp/pgsql_tmp62390.6721": No space left on device which I assume is because it's trying to temporarily save a list of every possible barcode before executing the query. I also tried adding some constraints inside the nested query, but I got another error there.
Could someone help me with the query?
Thank you very much for your time,
Bill

db2 - Bulk rows update with select on different tables

I wanted to update a column for multiple rows based on the below condition -
I want to update column AUUSRTX of file abhipsha/AUDUSERF only for those rows
WHERE AUDUSERF.AUUSRTP <> 'USR' and AUDUSERF.AUUSRTP <> 'usr'
and the value that needs to be updated have to come from usrprffil.uptext from usrprffil of the matching user id . User ids of both tables are as follows
usrprffil.upuprf = auduserf.auusrid
Can someone please help with a correct query for this requirement.
I wrote the below 3 queries but i am getting error as -"Result of SELECT more than one row" for 1st and 2nd query
query 1 -
update abhipsha/auduserf
set AUUSRTX = (
SELECT usrprffil.uptext
from usrprffil inner join
abhipsha/auduserf
on upuprf =auusrid WHERE AUDUSERF.AUUSRTP <> 'USR'
and auduserf.auusrtp <> 'usr' and auusrid = usrprffil.upuprf)
query 2 -
update abhipsha/auduserf set AUUSRTX =
(SELECT uptext fROM usrprffil inner
join abhipsha/auduserf
on usrprffil.UPUPRF = auduserf.AUUSRID
WHERE
usrprffil.UPUPRF in (
SELECT AUUSRID FROM abhipsha/auduserf
WHERE
AUUSRTP <> 'USR' and AUUSRTP <> 'usr'
)
)
for the 3rd query i am getting - null value error
query 3 -
update abhipsha/auduserf
set auduserf.AUUSRTX = (
select UPTEXT
from usrprffil
WHERE usrprffil.UPUPRF = auduserf.AUUSRID
and usrprffil.UPUPRF in
(SELECT AUUSRID FROM abhipsha/auduserf
WHERE AUUSRTP <> 'USR' and AUUSRTP <> 'usr')
and uptext <> ' ' and
uptext is not null )
Null values not allowed in column or variable AUUSRTX.
Try this:
update abhipsha/auduserf a
set AUUSRTX =
COALESCE
(
(
SELECT min(u.uptext)
from usrprffil u
WHERE a.auusrid = u.upuprf
)
, AUUSRTX
)
WHERE a.AUUSRTP NOT IN ('USR', 'usr')
Notes:
The min function is used to not return multiple rows from the sub-select.
If the sub-select returns no rows, the AUUSRTX column value remains as is.
You may adjust the logic above according to your needs, of course.

Unexpected "Subquery returned more than 1 value"

Tables have this structure: groupTable > lineGroupJoinTable > linesTable (name are obfuscated names)
I have the following query which returns this error:
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
The thing is that I expect that since the subquery is group, I should not get this error. I'm probably missing something.
UPDATE dbo.groupTable
SET fieldToUpdate = CASE WHEN fieldToUpdate IS NULL THEN NULL ELSE
(
SELECT sumTable.fieldToSum FROM
dbo.groupTable gt
INNER JOIN
(
SELECT lgjt.groupdId1, lgjt.groupdId2, SUM(lt.fieldToSum) as fieldToSum
FROM lineGroupJoinTable lgjt
INNER JOIN linesTable lt
ON
lt.fieldToSum IS NOT NULL AND lt.fieldToSum > 0 AND
lgjt.lineId1 = lt.lineId1 AND lgjt.lineId2 = lt.lineId2
GROUP BY lgjt.groupdId1, lgjt.groupdId2
) sumTable
ON sumTable.groupdId1 = gt.groupdId1 AND sumTable.groupdId2 = gt.groupdId2
)
END
This variation was also try following a suggestion but return the same error:
UPDATE dbo.groupTable
SET fieldToUpdate = CASE WHEN fieldToUpdate IS NULL THEN NULL ELSE
(
SELECT SUM(sumTable.fieldToSum) FROM
dbo.groupTable gt
INNER JOIN
(
SELECT lgjt.groupdId1, lgjt.groupdId2, SUM(lt.fieldToSum) as fieldToSum
FROM lineGroupJoinTable lgjt
INNER JOIN linesTable lt
ON
lt.fieldToSum IS NOT NULL AND lt.fieldToSum > 0 AND
lgjt.lineId1 = lt.lineId1 AND lgjt.lineId2 = lt.lineId2
GROUP BY lgjt.groupdId1, lgjt.groupdId2
) sumTable
ON sumTable.groupdId1 = gt.groupdId1 AND sumTable.groupdId2 = gt.groupdId2
GROUP BY gt.groupdId1, gt.groupdId2
)
END
Probably because dbo.groupTable has multiple value for the combination id1 and id2. I suggest to group on the id1 and id2 column and do a SUM, that case you will have only 1 result.
UPDATE dbo.groupTable
SET fieldToUpdate = CASE WHEN fieldToUpdate IS NULL THEN NULL ELSE
(
SELECT SUM(sumTable.fieldToSum) FROM
dbo.groupTable gt
INNER JOIN
(
SELECT lgjt.id1, lgjt.id2, SUM(lt.fieldToSum) as fieldToSum
FROM lineGroupJoinTable lgjt
INNER JOIN linesTable lt
ON
lt.fieldToSum IS NOT NULL AND lt.fieldToSum > 0 AND
lgjt.id3 = lt.id3 AND lgjt.id4 = lt.id4
GROUP BY lgjt.id1, lgjt.id2
) sumTable
ON sumTable.id1 = gt.id1 AND sumTable.id2 = gt.id2
GROUP BY gt.id1, gt.id2
)
END

Using the result of a subquery in a CASE expression with T-SQL

I'm writing a query with some CASE expressions and it outputs helper-data columns which help me determine whether or not a specific action is required. I would like to know if I can somehow use the result of a subquery as the output without having to perform the same query twice (between WHEN (subquery) THEN and as the result after THEN)
The dummy code below describes what I'm after. Can this be done? I'm querying a MS2005 SQL database.
SELECT 'Hello StackOverflow'
,'Thanks for reading this question'
,CASE
WHEN
(
SELECT count(*)
FROM sometable
WHERE condition = 1
AND somethingelse = 'value'
) > 0 THEN
-- run the query again to get the number of rows
(
SELECT count(*)
FROM sometable
WHERE condition = 1
AND somethingelse = 'value'
)
ELSE 0
END
SELECT 'Hello StackOverflow'
,'Thanks for reading this question'
,CASE
WHEN
(
SELECT count(*)
FROM sometable
WHERE condition = 1
AND somethingelse = 'value'
) AS subqry_count > 0 THEN
-- use the subqry_count, which fails... "Incorrect syntax near the keyword 'AS'"
subqry_count
ELSE 0
END
Just use the subquery as the source you are selecting from:
SELECT 'Hello StackOverflow'
,'Thanks for reading this question'
,CASE subqry_count.Cnt
WHEN 0 THEN 0
ELSE subqry_count.Cnt
END
FROM ( SELECT count(*) AS Cnt
FROM sometable
WHERE condition = 1
AND somethingelse = 'value'
) subqry_count
As an aside, if you are just going to return 0 if the output from COUNT is 0, then you don't even need to use a CASE statement.

How to use parameters in a SQL query with NOT EXISTS?

How can I change following query, so that I'm able to parameterize the SparePartNames?
It returns all ID's of repairs where not all mandatory spareparts were changed, in other words where at least one part is missing.
Note that the number of spareparts might change in future not only the names. Is it possible without using a stored procedure with dynamic SQL? If not, how could this SP look like?
Edit: Note that i do not need to know how to pass a list/array as parameter, this is asked myriads of time on SO. I've also already a Split table-valued-function. I'm just wondering how i could rewrite the query to be able to join(or whatever) with a list of mandatory parts, so that i'll find all records where at least one part is missing. So is it possible to use a varchar-parameter like '1264-3212,1254-2975' instead of a list of NOT EXISTS? Sorry for the confusion if it was not clear in the first place.
SELECT d.idData
FROM tabData d
INNER JOIN modModel AS m ON d.fiModel = m.idModel
WHERE (m.ModelName = 'MT27I')
AND (d.fiMaxServiceLevel >= 2)
AND (d.Manufacture_Date < '20120511')
AND (NOT EXISTS
(SELECT NULL
FROM tabDataDetail AS td
INNER JOIN tabSparePart AS sp ON sp.idSparePart = td.fiSparePart
WHERE (td.fiData = d.idData)
AND (sp.SparePartName = '1264-3212'))
OR (NOT EXISTS
(SELECT NULL
FROM tabDataDetail AS td
INNER JOIN tabSparePart AS sp ON sp.idSparePart = td.fiSparePart
WHERE (td.fiData = d.idData)
AND (sp.SparePartName = '1254-2975'))
)
)
Unfortunately I don't see how I could use sp.SparePartName IN/NOT IN(#sparePartNames) here.
One way to do it is to create a function to split delimited strings:
CREATE FUNCTION [dbo].[Split]
(
#Delimiter char(1),
#StringToSplit varchar(512)
)
RETURNS table
AS
RETURN
(
WITH Pieces(pieceNumber, startIndex, delimiterIndex)
AS
(
SELECT 1, 1, CHARINDEX(#Delimiter, #StringToSplit)
UNION ALL
SELECT pieceNumber + 1, delimiterIndex + 1, CHARINDEX(#Delimiter, #StringToSplit, delimiterIndex + 1)
FROM Pieces
WHERE delimiterIndex > 0
)
SELECT
SUBSTRING(#StringToSplit, startIndex, CASE WHEN delimiterIndex > 0 THEN delimiterIndex - startIndex ELSE 512 END) AS Value
FROM Pieces
)
populate a table variable with the spare part names:
DECLARE #SpareParts TABLE
(
SparePartName varchar(50) PRIMARY KEY CLUSTERED
);
INSERT INTO #SpareParts
SELECT Value FROM dbo.Split(',', '1264-3212,1254-2975');
and then join to the table variable:
SELECT d.idData
FROM tabData d
INNER JOIN modModel AS m ON d.fiModel = m.idModel
WHERE (m.ModelName = 'MT27I')
AND (d.fiMaxServiceLevel >= 2)
AND (d.Manufacture_Date < '20120511')
AND EXISTS (
SELECT 1
FROM tabDataDetail AS td
INNER JOIN tabSparePart AS sp ON sp.idSparePart = td.fiSparePart
LEFT JOIN #SpareParts AS s ON s.SparePartName = sp.SparePartName
WHERE td.fiData = d.idData
AND s.SparePartName IS NULL
)
Assuming there is (or will be) a table or view of mandatory spare parts, a list of exists can be replaced with a left join to tabDataDetail / tabSparePart pair on SparePartName; non-matches are reported back using td.fiSparePart is null.
; with mandatorySpareParts (SparePartName) as (
select '1264-3212'
union all
select '1254-2975'
)
SELECT d.idData
FROM tabData d
INNER JOIN modModel AS m ON d.fiModel = m.idModel
WHERE (m.ModelName = 'MT27I')
AND (d.fiMaxServiceLevel >= 2)
AND (d.Manufacture_Date < '20120511')
AND exists
(
SELECT null
from mandatorySpareParts msp
left join ( tabDataDetail AS td
INNER JOIN tabSparePart AS sp
ON sp.idSparePart = td.fiSparePart
AND td.fiData = d.idData
)
ON msp.SparePartName = sp.SparePartName
WHERE td.fiSparePart is null
)
Part names should be replaced by their id's, which would simplify left join and speed the query up.
EDIT: i've errorneously left filtering of td in where clause, which invalidated left join. It is now in ON clause where it belongs.
Use a table-variable and join on that.