Correlated subquery in order by clause in DB2 - db2

I had a query similar to the following and was wondering that DB2 complained about the correlation use in the ORDER BY clause. It errored with something like
[42703][-206] "A.ID" is not valid in the context where it is used..
SQLCODE=-206, SQLSTATE=42703
I was able to rewrite the query to avoid the correlation usage but I couldn't find a reference in the documenation about this. Is this a bug or am I just not able to find details on the expected behavior?
SELECT a.id
FROM A a
ORDER BY (
SELECT COUNT(*)
FROM B b
WHERE b.id = a.id
)

You can't use correlated query in order by clause. However there is many ways to get same result, for example
select count(*) as count_num ,a.ID
from
a join b on a.ID=b.ID
GROUP BY a.ID
order by 1 DESC

solution 1:
SELECT a.id, (select count(*) from B where B.id=a.id) nbOFB
FROM A
order by 2

solution 2:
select * from (
SELECT a.id, (select count(*) from B where B.id=a.id) nbOFB
FROM A
) tmp
order by nbOFB

Solution 3:
SELECT a.id, c.nb
FROM A
inner join lateral
(
select count(*) nb from B where B.id=a.id
) c on 1=1
order by c.nb

Solution 4 :
SELECT a.id, ifnull(c.nb, 0) nb
FROM A
left outer join
(
select b.id, count(*) nb from B group by b.id
) c on a.id=c.id
order by ifnull(c.nb, 0)

Solution 5:
with c as (
select b.id, count(*) nb from B group by b.id
)
SELECT a.id, ifnull(c.nb, 0) nb
FROM A left outer join c on a.id=c.id
order by ifnull(c.nb, 0)

Related

How to add id sequence from select query in postgresql

I would like to add sequence id after I select data from more than one table
this is my query:
SELECT DISTINCT a.value_suggested_row, c.id as question_id, c.question, b.value
from survey_user_input_line a
LEFT JOIN survey_label b on b.id = a.value_suggested_row
LEFT JOIN survey_question c on c.id = a.question_id
where survey_id = 6
ORDER BY question_id
and this is the result
how to do the correct query to add the id sequence to the query so that the results are like this
Can Anyone help me, please?
In the select list add ROW_NUMBER () OVER (ORDER BY question_id) as id_sequence
SELECT DISTINCT #rownum:=#rownum+1 id_sequence, a.value_suggested_row, c.id as
question_id, c.question, b.value
from survey_user_input_line a
LEFT JOIN survey_label b on b.id = a.value_suggested_row
LEFT JOIN survey_question c on c.id = a.question_id
where survey_id = 6
ORDER BY question_id, (SELECT #rownum:=0) r;

How to use aggregate functions when using recursive query in postgresql

On multiple iteration on a recursive query in postgresql, I have got the following result when i run the below query
WITH recursive report AS (
select a.name, a.id, a.parentid, sum(b.id)
from table1 a
INNER JOIN table2 b on a.id=b.table1id
GROUP by a.name, a.id, a.parentid
), report2 AS (
SELECT , 0 as lvl
FROM report
WHERE parentid IS NULL
UNION ALL
SELECT child., parent.lvl + 1
FROM report child
JOIN report2 parent
ON parent.id = child.parentid
)
select * from report2
I want to sum the count column with the top most level, so my output should be like below,
What is the best possible way to get it.
If you calculate a path during recursion, like so:
WITH recursive report AS (
select a.name, a.id, a.parentid, sum(b.id) -- Is summing b.id the right thing here?
from table1 a
INNER JOIN table2 b on a.id=b.table1id
GROUP by a.name, a.id, a.parentid
), report2 AS (
SELECT report.*, 0 as lvl, array[report.id] as path_array
FROM report
WHERE parentid IS NULL
UNION ALL
SELECT child.*, parent.lvl + 1, report2.path_array||report.id
FROM report child
JOIN report2 parent
ON parent.id = child.parentid
)
select * from report2;
Do you really mean sum(b.id) and not count(*) in the report CTE?
You can get the sum of count for your top levels using this query as the main query from your recursion:
select t.name, sum(r.count) as total_count
from report2 r
join table1 t
on t.id = r.path_array[1]
group by t.name;

How to rewrite query?

I can easily select rows which I should update.
select
p.id,
(regexp_match( p.name, '\d+'))[1] as renum,
pd.quantity
from package p
left join package_detail pd on
pd.package_id = p.id and resource_type_id is null
where p.name like '%Bit%';
But how to write query to update quantity by renum from the result above?
I am not looking for the query. I am looking the rule to complete this task.
You can find background in the docs (https://www.postgresql.org/docs/current/sql-update.html ) but if you've got a query that gives the result you want, you can use that query as a correlated subquery in the update command:
UPDATE table1 t1 SET (col1, col2, col3) = (select t2.val1, t2.val2, t2.val3 from table2 t2 where t2.table1_id = t1.id)
WHERE t1.col1 IS NULL
In your case, this might take the form or something similar to:
UPDATE package p2 SET (quantity) = (
select ((regexp_match( p.name, '\d+'))[1])::integer + pd.quantity
from package p
left join package_detail pd on pd.package_id = p.id and resource_type_id is null
where p.name like '%Bit%'
and p2.id = p.id
and ((regexp_match( p.name, '\d+'))[1])::integer + pd.quantity IS NOT NULL )
WHERE p2.name like '%Bit%'

Avoiding Order By in T-SQL

Below sample query is a part of my main query. I found SORT operator in below query is consuming 30% of the cost.
To avoid SORT, there is need of creation of Indexes. Is there any other way to optimize this code.
SELECT TOP 1 CONVERT( DATE, T_Date) AS T_Date
FROM TableA
WHERE ID = r.ID
AND Status = 3
AND TableA_ID >ISNULL((
SELECT TOP 1 TableA_ID
FROM TableA
WHERE ID = r.ID
AND Status <> 3
ORDER BY T_Date DESC
), 0)
ORDER BY T_Date ASC
Looks like you can use not exists rather than the sorts. I think you'll probably get a better performance boost by use a CTE or derived table instead of the a scalar subquery.
select *
from r ... left outer join
(
select ID, min(t_date) as min_date from TableA t1
where status = 3 and not exists (
select 1 from TableA t2
where t2.ID = t1.ID
and t2.status <> 3 and t2.t_date > t1.t_date
)
group by ID
) as md on md.ID = r.ID ...
or
select *
from r ... left outer join
(
select t1.ID, min(t1.t_date) as min_date
from TableA t1 left outer join TableA t2
on t2.ID = t1.ID and t2.status <> 3
where t1.status = 3 and t1.t_date < t2.t_date
group by t1.ID
having count(t2.ID) = 0
) as md on md.ID = r.ID ...
It also appears that you're relying on an identity column but it's not clear what those values mean. I'm basically ignoring it and using the date column instead.
Try this:
SELECT TOP 1 CONVERT( DATE, T_Date) AS T_Date
FROM TableA a1
LEFT JOIN (
SELECT ID, MAX(TableA_ID) AS MaxAID
FROM TableA
WHERE Status <> 3
GROUP BY ID
) a2 ON a2.ID = a1.ID AND a1.TableA_ID > coalesce(a2.MAXAID,0)
WHERE a1.ID = r.ID AND a1.Status = 3
ORDER BY T_Date ASC
The use of TOP 1 in combination with the unexplained r alias concern me. There's almost certainly a MUCH better way to get this data into your results that doesn't involve doing this in a sub query (unless this is for an APPLY operation).

SQL Join Statement Issue

I'm tring to grab all fields from the latest Cash record, and then all fields from the related TransactionInfo record. I can't quite get this to work yet:
select t.*, top 1 c.* from Cash c
inner join TransactionInfo t
on c.TransactionID = t.id
order by c.createdOn desc
select top 1 *
from Cash c
inner join TransactionInfo t on c.TransactionID = t.id
order by createdOn desc
What's that top 1 doing there? If you only want one row then the TOP(1) must come first:
SELECT TOP(1) t.*, c.*
FROM Cash c
INNER JOIN TransactionInfo t
ON c.TransactionID = t.id
ORDER BY c.createdOn DESC
select t.,c.
from (Select top 1 * from Cash order by createdOn desc
) c
inner join TransactionInfo t
on c.TransactionID = t.id
order by createdOn desc
DOn;t use select * especially with a join, it wastes server resources.
SELECT c.*, t.* FROM cash c, transactioninfo t
WHERE c.infoid = t.id AND c.createdOn = (SELECT max(createdOn) FROM cash WHERE infoId = t.id) ORDER BY transactiontabledate desc
You need to find the record with the latest date from the cash table for each transactionId and use that also to filter it out in your query.