How to grouping row value in some conditional postgresql - sql

I have query like this:
SELECT user_input_id,
question_id,
type,
question,
COALESCE(value_text, value_free_text, value_date::text, value_number::text, value) AS all_value
FROM(
SELECT
a.id,
a.user_input_id,
d.id as question_id,
d.type,
d.matrix_subtype,
d.question,
a.value_suggested_row,
c.value as matrix_questions,
a.value_suggested,
b.value,
a.value_text,
a.value_free_text,
a.value_date,
a.value_number
FROM survey_user_input_line a
LEFT JOIN survey_label b on b.id = a.value_suggested
LEFT JOIN survey_label c on c.id = a.value_suggested_row
LEFT JOIN survey_question d on d.id = a.question_id
LEFT JOIN survey_user_input e on e.id = a.user_input_id
WHERE a.survey_id = 6
ORDER BY question_id, a.user_input_id, id, value_suggested_row) as TempTable
and this result:
I would like to grouping row where type is multiple_choice
and my wish result like this:
Can Anyone Help Me?

I would split your result into two part (with and without multiple_choice) and UNION them after grouping the multiple_choice part:
SELECT
*
FROM (--<your query>) s
WHERE type != 'multiple_choice'
UNION
SELECT
user_input_id,
question_id,
type,
question,
STRING_AGG(all_value, ',')
FROM (--<your query>) s
WHERE type = 'multiple_choice'
GROUP BY user_input_id, question_id, type, question
It could be more performant to put your subquery into a CTE:
WITH my_cte AS (
-- <your query>
)
SELECT
*
FROM my_cte
WHERE type != 'multiple_choice'
UNION
SELECT
user_input_id,
question_id,
type,
question,
STRING_AGG(all_value, ',')
FROM my_cte
WHERE type = 'multiple_choice'
GROUP BY user_input_id, question_id, type, question

Related

find all card numbers in which the largest id oracle

I have a request. It works but I can't upgrade it. I want it to show not all records from id cards, but only in which the largest id, that is can be that there are records from id cards, but at one id 100, and at another also record 101, I want that in the answer there was only record from 101.
select a.id,
a.employee_id,
a.STATUS,
a.expiration_date,
a.ID_CARD
from EM_STATUS_CARD a
left join EM_CARD b on a.ID_CARD = b.ID_CARD
where b.del != 'true' or b.del is null
Its good practice to provide a sample data and expected result but in the absence of these information I believe you are looking for something like below query.
with main_query as (select a.id,
a.employee_id,
a.STATUS,
a.expiration_date,
a.ID_CARD
from EM_STATUS_CARD a
left join EM_CARD b on a.ID_CARD = b.ID_CARD
where b.del != 'true' or b.del is null)
select x.id, y.employee_id, y.id_card, y.status, y.expiration from
(select max(id) id, id_card from main_query group by id_card) x, main_query y
where a.id_card = b.id_card;
Should work just fine. I did some refactoring, as Oracle supports using for join
select id,
employee_id,
STATUS,
expiration_date,
ID_CARD
from EM_STATUS_CARD
left join EM_CARD using(ID_CARD)
where (del != 'true' or del is null) and id = (
select max(id)
from EM_STATUS_CARD
)

SQL select specific rows from subquery and insert into row_to_json

I have a view for which I have created several subqueries, I'm trying to return one of the subqueries as json using -
row_to_json(err.*) as overall_totals
The subquery -
left join
(
SELECT q.id, SUM(q.total) AS total,
jsonb_agg(jsonb_build_object('count', q.total, 'type', q.name)) AS totals
FROM (
SELECT r.id AS id, e.name, COUNT(de.value_id) AS total
FROM table_c de
JOIN tests.error e
ON e.id = de.value_id
JOIN table_a p
ON de.process_id = p.id
Join table_b r on p.root = r.id
GROUP BY e.name, r.id ) q
GROUP BY q.id
) err on err.id = rs.id
This works fine and returns as json, however, I only want to return total and totals of the "err" sub-query and not q.id. I need the q.id in the sub-query so that I can join the query onto the rest of the view but I don't want it to be stored in overall_totals. How can I get around this? Is it possible to select certain values into row_to_json?
If you are fine with returning jsonb instead of json, then you can use the - operator:
to_jsonb(err.*) - 'id' as overall_totals
You can add more subquery, something like this
SELECT row_to_json(err2.*) as overall_totals
FROM
(
SELECT err.total, err.totals
FROM XXX_TABLE RS
left join
(
SELECT q.id, SUM(q.total) AS total, jsonb_agg(jsonb_build_object('count', q.total, 'type', q.name)) AS totals
FROM
(
SELECT r.id AS id, e.name, COUNT(de.value_id) AS total
FROM table_c de
JOIN tests.error e
ON e.id = de.value_id
JOIN table_a p
ON de.process_id = p.id
Join table_b r on p.root = r.id
GROUP BY e.name, r.id
) q
GROUP BY q.id
) err on err.id = rs.id
) err2

Oracle SQL Correlated subquery - Returning count(*) in some columns

I have my initial statement which is :
SELECT TEAM.ID PKEY_SRC_OBJECT,
TEAM.MODF_DAT UPDATE_DATE,
TEAM.MODF_USR UPDATED_BY,
PERSO.FIRST_NAM FISRT_NAME
FROM TEAM
LEFT OUTER JOIN PERSO ON (TEAM.ID=PERSO.TEAM_ID)
I want to calculate some "flags" and return them in my initial statement.
There are 3 flags which can be calculated like this :
1) Flag ISMASTER:
SELECT Count(*)
FROM TEAM_TEAM_REL A, TEAM B
WHERE B.PARTY_PTY_ID = A.RLTD_TEAM_ID
AND CODE = 'Double';
2) Flag ISAGENT:
SELECT Count(*)
FROM TEAM_ROL_REL A, TEAM B
WHERE B.PARTY_PTY_ID = A.TEAM_ID;
3) Flag NUMPACTS:
SELECT Count(*)
FROM TEAM_ROL_REL A,
TEAM_ROL_POL_REL B,
PERSO_POL_STA_REL C,
TEAM D
WHERE A.ROL_CD IN ('1','2')
AND A.T_ROL_REL_ID = B.P_ROL_REL_ID
AND B.P_POL_ID = C.P_POL_ID
AND C.STA_CD = 'A'
AND D.PARTY_PTY_ID = A.TEAM_ID;
To try to achieve this, I've updated my initial statement like this :
WITH ABC AS (
SELECT TEAM.ID PKEY_SRC_OBJECT,
TEAM.MODF_DAT UPDATE_DATE,
TEAM.MODF_USR UPDATED_BY,
PERSO.FIRST_NAM FISRT_NAME
FROM TEAM
LEFT OUTER JOIN PERSO ON (TEAM.ID=PERSO.TEAM_ID)
)
SELECT ABC.*, MAST.ISMASTER, AGENT.ISAGENT, PACTS.NUMPACTS FROM ABC
LEFT OUTER JOIN (
select
RLTD_TEAM_ID,
Count(RLTD_TEAM_ID) OVER (PARTITION BY RLTD_TEAM_ID) as ISMASTER
FROM TEAM_TEAM_REL
WHERE CODE = 'Double'
) MAST
ON ABC.PKEY_SRC_OBJECT = MAST.RLTD_TEAM_ID
LEFT OUTER JOIN (
select
TEAM_ID,
Count(TEAM_ID) OVER (PARTITION BY TEAM_ID) as ISAGENT
FROM TEAM_ROL_REL
) AGENT
ON ABC.PKEY_SRC_OBJECT = AGENT.TEAM_ID
LEFT OUTER JOIN (
select
TEAM_ID,
Count(TEAM_ID) OVER (PARTITION BY TEAM_ID) as NUMPACTS
FROM TEAM_ROL_REL, TEAM_ROL_POL_REL, PERSO_POL_STA_REL
WHERE TEAM_ROL_REL.ROL_CD IN ('1','2')
AND TEAM_ROL_REL.T_ROL_REL_ID = TEAM_ROL_POL_REL.P_ROL_REL_ID
AND TEAM_ROL_POL_REL.P_POL_ID = PERSO_POL_STA_REL.P_POL_ID
AND PERSO_POL_STA_REL.STA_CD = 'A'
) PACTS
ON ABC.PKEY_SRC_OBJECT = PACTS.TEAM_ID;
For the two first flags (ISMASTER and ISAGENT) I get the result in less than 1min, but for the last flag (NUMPACTS) it runs few minutes without provide any result.
I think my statement is too heavy, maybe I should do it in a totally different way.
I think you have perhaps over complicated things.
You could do this (assuming I have understood your requirements correctly) like so:
WITH ttr AS (SELECT rltd_team_id,
COUNT(*) is_master
FROM team_team_rel
AND CODE = 'Double'
GROUP BY rltd_team_id),
trr AS (SELECT team_id,
COUNT(*) is_agent
FROM team_rol_rel
GROUP BY team_id)
pacts AS (SELECT trr1.team_id,
COUNT(*) num_pacts
FROM team_rol_rel trr1
INNER JOIN team_rol_pol_rel trpr ON (trr1.t_rol_rel_id = trpr.p_rol_rel_id)
INNER JOIN perso_pol_sta_rel ppsr ON (trpr.p_pol_id = ppsr.p_pol_id
WHERE trr1.rol_cd IN ('1', '2')
AND ppsr.st_cd = 'A'
GROUP BY trr1.team_id)
SELECT t.id pkey_src_object,
t.modf_dat update_date,
t.modf_usr updated_by,
p.first_nam first_name,
ttr.is_master,
trr.is_agent,
pacts.num_pacts
FROM team t
LEFT OUTER JOIN perso p ON t.id = p.team_id
LEFT OUTER JOIN ttr ON t.party_pty_id = ttr.rltd_team_id
LEFT OUTER JOIN trr ON t.party_pty_id = trr.team_id
LEFT OUTER JOIN pacts ON t.pkey_src_object = pacts.team_id;
N.B. untested, since you didn't provide any test data.

How to use BigQuery's union all with an inner join?

I am attempting to join all comment tables (shards of comments each month) to a posts table. Is there a way for me to perform a union all before the inner join? Details on the union all operator can be found in the documentation here. My query with only 1 of the comments table is as follows:
SELECT c.score, c.body, c.link_id, c.parent_id, p.created_utc, c.created_utc
FROM [fh-bigquery:reddit_comments.2016_01] AS c
INNER JOIN [fh-bigquery:reddit_posts.full_corpus_201512] AS p
ON c.parent_id = p.name
WHERE SUBSTR(c.parent_id, 1, 2) = 't3'
ORDER BY c.score DESC
LIMIT 10
Replace
FROM [fh-bigquery:reddit_comments.2016_01] AS c
with
FROM (
SELECT score, body, link_id, parent_id, created_utc
FROM (TABLE_QUERY([fh-bigquery:reddit_comments],
'REGEXP_MATCH(table_id, r"\d{4}_\d{2}")'))
) AS c
Hope, this gives you idea
See more on Table wildcard functions and Regular expression functions
As Mikhail Berlyant pointed out in his answer, modifying the query as such accomplished what I needed.
SELECT c.score, c.body, c.link_id, c.parent_id, p.created_utc, c.created_utc, (c.created_utc - p.created_utc) AS time_diff
FROM (
SELECT *
FROM
[fh-bigquery:reddit_comments.2015_11],
[fh-bigquery:reddit_comments.2015_12],
[fh-bigquery:reddit_comments.2016_01],
) AS c
INNER JOIN [fh-bigquery:reddit_posts.full_corpus_201512] AS p
ON c.parent_id = p.name
WHERE SUBSTR(c.parent_id, 1, 2) = 't3'
ORDER BY c.score DESC
LIMIT 100

how to join a table on a subquery that uses order by and limit

For each row from table tClass matching a given where clause,
join on the first row in tEv, sorted by time, where tEv.class_id = tClass.class_id
The following code throws the error
ORA-01799: a column may not be outer-joined to a subquery
select
c.class_id,
c.class_name,
e.start_time,
e.ev_id
from
tClass c
left join tEv e on (
e.ev_id = (
select
ss1.ev_id
from (
select
ed.ev_id
from
tEvDisp ed,
tEv e
where
ed.class_id = c.class_id
and ed.viewable = 'Y'
and ed.display_until > localtimestamp
and e.ev_id = ed.ev_id
order by
e.start_time
) ss1
where
rownum = 1
)
)
where
c.is_matching = 'Y';
How can this be rewritten to do what is described?
The above is for oracle, but needs to work in sqlite (substituting where necessary)
No idea about SQLite - that would need to be a separate question if this doesn't work - but for Oracle you could do something like this:
select c.class_id,
c.class_name,
e.start_time,
e.ev_id
from tClass c
left join (
select class_id, ev_id, start_time
from (
select ed.class_id,
ed.ev_id,
e.start_time,
row_number() over (partition by ed.class_id order by e.start_time) as rn
from tEvDisp ed
join tEv e on e.ev_id = ed.ev_id
where ed.viewable = 'Y'
and ed.display_until > localtimestamp
)
where rn = 1
) e on e.class_id = c.class_id
where c.is_matching = 'Y';
This uses a subquery which finds the most tEv data, using an analytic row_number() to identify the latest data for each class_id, which is restricted by the rn = 1 filter.
That subquery, consisting of at most one row per class_id, is then used the left outer join against tClass.
This sort of construct should get you what you need. You can fix the details.
select c.classid
, c.classname
, temp.maxstarttime
from tClass c left join (
select c.classid id
max(e.start_time) maxstarttime
from tClass join tEv on tEv.classId = tClass.ClassId
where whatever
group by c.classid) temp on c.classid = temp.id