Recursive SQL query only returning single reference instead of recursive references - sql

I have a DB table
id (INT, NOT NULL)
username (NVARCHAR, NOT NULL)
holiday_replacement (INT, NULL)
The holiday_replacement is either NULL or it references a value in the id field.
Now, it would be trivial to determine for whom a specified id was the holiday_replacement, but to complicate this query the holiday_replacement may be chained.
In simpler terms, a user may have a holiday_replacement who themselves has a holiday_replacement.
In such a case the query should return a list of all users in this 'holiday replacement graph'.
Currently I have
WITH user_graph AS (
SELECT
*
FROM
table_name
WHERE
holiday_replacement = #current_user_id
UNION ALL
SELECT
tn.*
FROM
table_name tn
JOIN user_graph ug ON ug.holiday_replacement = tn.id
)
SELECT
id
FROM
user_graph
However, this query only returns those users who have directly referenced #current_user_id as their holiday_replacement and doesn't consider any other users who should also be returned on account of this chaining.
For example, if I have the following 3 users:
id = 1, username = 'user_1', holiday_replacement = NULL
id = 2, username = 'user_2', holiday_replacement = 1
id = 3, username = 'user_3', holiday_replacement = 2
then for #current_user_id = 1, the query should return
id
---
2
3
but presently it only considers that directly referenced user and returns
id
---
2
I just can't wrap my head around what I need to change. Can anyone help?

use below code
WITH user_graph AS (
SELECT
*
FROM
table_name
WHERE
holiday_replacement = #current_user_id
UNION ALL
SELECT
tn.*
FROM
table_name tn
JOIN user_graph ug ON ug.id =tn.holiday_replacement
)
SELECT
id FROM
user_graph

Related

How do i create a DB2 UNION query using variables from a list

So i have a union query like:
select count(id)
from table 1
where membernumber = 'x'
and castnumber = 'y'
union
select count(id)
from table 1
where membernumber = 'x'
and castnumber = 'y'
union
etc...
There will be over 200 unions coming from a list 2x 200 table with values for x and y in each row. So each union query has to get the value of x and y from the corresponding row (not in any particular order).
How can i achieve that ?
Thanks
Try this:
DECLARE GLOBAL TEMPORARY TABLE
SESSION.PARAMETERS
(
MEMBERNUMBER INT
, CASTNUMBER INT
) DEFINITION ONLY WITH REPLACE
ON COMMIT PRESERVE ROWS NOT LOGGED;
-- Insert all the the constants in your application with
INSERT INTO SESSION.PARAMETERS
(MEMBERNUMBER, CASTNUMBER)
VALUES (?, ?);
-- I don't know the meaning of the result you want to get
-- but it's equivalent
select distinct count(t.id)
from table1 t
join session.parameters p
on p.membernumber = t.membernumber
and p.castnumber = t.castnumber
group by t.membernumber, t.castnumber;

How to return a value with COALESCE when a SELECT statement returns nothing?

Hello Stackoverflow community !
I got this code :
(SELECT COALESCE(id, 0) FROM members WHERE user_id = 1225282512438558720)
UNION ALL
(SELECT COALESCE(id, 0) FROM channels WHERE channel_id = 720694686028791971)
UNION ALL
(SELECT COALESCE(id, 0) FROM guilds WHERE guild_id = 831900150115991605);
Each statement could or not could return a value (because nothing corresponds to the WHERE Clause)
My problem is that if for example the first statement returns nothing then Postgres is going to return me this
coalesce
----------
6
1
but i want that Postgres returns me this :
coalesce
----------
NULL
6
1
How can i do that ?
This query returns nothing because no rows satisfy filter criteria. To return rows from the empty result set you need to do aggregation. So you need:
(SELECT max(id) FROM members WHERE user_id = 1225282512438558720)
UNION ALL
(SELECT max(id) FROM channels WHERE channel_id = 720694686028791971)
UNION ALL
(SELECT max(id) FROM guilds WHERE guild_id = 831900150115991605);
For multiple columns or results, you can left-join an unary row table to each of your inputs
WITH dual AS (select 1)
(SELECT COALESCE(id, 0) FROM dual LEFT JOIN members ON user_id = 1225282512438558720)
UNION ALL
(SELECT COALESCE(id, 0) FROM dual LEFT JOIN channels ON channel_id = 720694686028791971)
UNION ALL
(SELECT COALESCE(id, 0) FROM dual LEFT JOIN guilds ON guild_id = 831900150115991605);

Exclude value if they share the same ID

I have this statement in my Access database:
It lists Magazzino.Codice from 2 tables and the relating quantities.
SELECT Magazzino.Codice, Magazzino.Qnt
FROM Magazzino
WHERE (((Magazzino.[Prossimo_arrivo]) Is Null) And ((Magazzino.Qnt)<30) And ((Magazzino.[Fascia_I])=True));
UNION ALL --Joins allowing duplicates
SELECT Magazzino.Codice, Magazzino.Qnt
FROM Magazzino
WHERE (((Magazzino.[Prossimo_arrivo]) Is Null) And ((Magazzino.Qnt)<10) And ((Magazzino.[Fascia_II])=True));
I wish to add a statement avoiding to list Magazzino.Codice if the same ID is present on a third table Magazzino Grezzi.
How can I get this?
First, simplify the logic assuming you don't want duplicates form this table:
SELECT m.Codice, m.Qnt
FROM Magazzino as m
WHERE m.[Prossimo_arrivo]) Is Null AND
( (m.Qnt < 30 AND m.[Fascia_I] = True) OR
(m.Qnt < 10 AND m.[Fascia_II] = False) OR
)
Then use IN or EXISTS:
SELECT m.Codice, m.Qnt
FROM Magazzino as m
WHERE m.[Prossimo_arrivo]) Is Null AND
( (m.Qnt < 30 AND m.[Fascia_I] = True) OR
(m.Qnt < 10 AND m.[Fascia_II] = False) OR
) AND
NOT EXISTS (SELECT 1
FROM Magazzino_Grezzi as mg
WHERE mg.Codice = m.Codice
);
If you really want some rows to be duplicated (those that meet both conditions), then you can add the NOT EXISTS clause to both your subqueries.

select subquery using data from the select statement?

I have two tables, headers and lines. I need to grab the batch_submission_date from the header table, but sometimes a query for batch_id will return a null for batch_submission_date, but will also return a parent_batch_id, and if we query THAT parent_batch_id as a batch_id, it will then return the correct batch_submission_date.
e.g.
SELECT t1.batch_id,
t1.parent_batch_id,
t2.batch_submission_date
FROM db.headers t1, db.lines t2
WHERE t1.batch_id = '12345';
output = 12345, 99999, null
Then we use that parent batch_id as a batch_id :
SELECT t1.batch_id,
t1.parent_batch_id,
t2.batch_submission_date
FROM db.headers t1, db.lines t2
WHERE t1.batch_id = '99999';
and we get output = 99999,99999,'2018-01-01'
So I'm trying to write a query that will do this for me - anytime a batch_id's batch_submission_date is null, we find that batch_id's parent batch_id and query that instead.
This was my idea - but I just get back null both for bp_batch_submission_date and for new_submission_date.
SELECT
t1.parent_id as parent_id,
t1.BATCH_ID as bp_batch_id,
t2.BATCH_LINE_NUMBER as bp_batch_li,
t1.BATCH_SUBMISSION_DATE as bp_batch_submission_date,
CASE
WHEN t1.BATCH_SUBMISSION_DATE is null
THEN
(SELECT a.BATCH_SUBMISSION_DATE
FROM
db.headers a,
db.lines b
WHERE
a.SD_BATCH_HEADERS_SKEY = b.SD_BATCH_HEADERS_SKEY
and a.parent_batch_id = bp_batch_id
and b.batch_line_number = bp_batch_li
) END as new_submission_date
FROM
db.headers t1,
db.lines t2
WHERE
t1.SD_BATCH_HEADERS_SKEY = t2.SD_BATCH_HEADERS_SKEY
and (t1.BATCH_ID = '12345' or t1.PARENT_BATCH_ID = '12345')
and t2.BATCH_LINE_NUMBER = '1'
GROUP BY
t2.BATCH_CLAIM_LINE_STATUS_DESC,
t1.PARENT_BATCH_ID,
t1.BATCH_ID,
t2.BATCH_LINE_NUMBER,
t1.BATCH_SUBMISSION_DATE;
is what I'm trying to do possible? using the bp_batch_id and bp_batch_li variables
Use CTE (common table expression) to avoid redundant code, then use coalesce() to find parent date in case of null. In your first queries you didn't attach joining condition between two tables, I assumed it's based on sd_batch_headers_skey like in last query.
dbfiddle demo
with t as (
select h.batch_id, h.parent_batch_id, l.batch_submission_date bs_date
from headers h
join lines l on l.sd_batch_headers_skey = h.sd_batch_headers_skey
and l.batch_line_number = '1' )
select batch_id, parent_batch_id,
coalesce(bs_date, (select bs_date from t x where x.batch_id = t.parent_batch_id)) bs_date
from t
where batch_id = 12345;
You could use simpler syntax with connect by and level <= 2 but if in your data there are really rows containing same ids (99999, 99999) then we get cycle error.

SQL select statement in where clause

Hi there I am trying to execute a query but cannot seem to get it right.
SELECT *
FROM table
WHERE id IN (SELECT *
FROM table
WHERE description = 'A')
AND description = 'B'
Above is the query that I have got, the select * from table where description = A works as expected when ran alone I just need to make the where clause to work so I can see any id that has a description of A and B.
You will be getting multiple columns from the sub query when I assume you only want the id column:
SELECT *
FROM table
WHERE id IN (SELECT id
FROM table
WHERE description = 'A')
AND description = 'B'
No need for the select in the where clause
SELECT *
FROM table
WHERE id IN ('A', 'B')
Try this:
SELECT *
FROM table
WHERE description IN ('A', 'B')
it should be:
select * from table where id in (select id from table where description = 'A') and description = 'B'
but this query will give you zero result as you select records with description = 'A' and description = 'B', if you want to get records with either description of A or B, then you should write as
select * from table where description = 'A' or description = 'B'
or
select * from table where description in ('A','B')
SELECT distinct AnaTablo.Id , AnaTablo.FirmaAdi , AnaTablo.FirmaId , AnaTablo.KayitTarihi ,
users.Email Personel, (SELECT top 1 sabitler.Ayar from tblSabitAyarlar sabitler WHERE sabitler.Tur = 29 and sabitler.Deger in
(SELECT top 1 IslemId from tblEFaturaTakipIslem Islem WHERE AnaTablo.Id = Islem.EFaturaTakipId order by KayitTarihi desc))YapilanIslem,
AnaTablo.Eposta , AnaTablo.Aciklama
from tblEFaturaTakip AnaTablo left join AspNetUsers users on AnaTablo.PersonelId = users.Id