MyBatis SELECT query with IF condition - sql

I have a table sample_table like this
+-------+-------+-------+-------+-------------+
| pkey1 | pkey2 | mode | type | type_number |
+-------+-------+-------+-------+-------------+
| 001 | 01 | light | type1 | 1234 |
| 001 | 02 | light | type2 | 2345 |
| 002 | 01 | dark | type1 | 3456 |
| 002 | 02 | dark | type2 | 4567 |
+-------+-------+-------+-------+-------------+
I have a MyBatis SELECT query pseudo-code like this
SELECT
Master.pkey1,
Master.pkey2,
Master.mode,
Master.type,
T1.selectedNumber type_number
FROM
( SELECT * from sample_table)
as Master
left join (select type_number as selectedNumber from sample_table where type='type1') as T1
ON T1.pkey1 = Master.pkey1
left join (select type_number as selectedNumber from sample_table where type='type2') as T2
ON T2.pkey1 = Master.pkey1)
Is there a way to select from T1 or T2 based on the value in mode, like
SELECT
Master.pkey1,
Master.pkey2,
Master.mode,
Master.type,
if Master.type='light'
T1.selectedNumber type_number
if Master.type='dark'
T2.selectedNumber type_number
My expected result is something like this
+-------+-------+-------+-------+-------------+
| pkey1 | pkey2 | mode | type | type_number |
+-------+-------+-------+-------+-------------+
| 001 | 01 | light | type1 | 1234 |
| 001 | 02 | light | type2 | 1234 |
| 002 | 01 | dark | type1 | 4567 |
| 002 | 02 | dark | type2 | 4567 |
+-------+-------+-------+-------+-------------+
Edit: Added Some extra code and the expected result

How about just using window functions?
select s.*,
(case when mode = 'light'
then max(case when type = 'type1' then type_number end) over (partition by pkey1)
else max(case when type = 'type2' then type_number end) over (partition by pkey2)
end)
from sample_table s;

Related

Get value from Table A if exist else get value from TABLE B. If multiple values are found return MT to indicate multiple types

Get value from Table A if exist else get value from TABLE B. If multiple values are found return MT to indicate multiple types.
For example, if trying to lookup a name that has 'c' and type = 'SW'
the following result is expected
Name | NUM | ID | TYPE
--------------------------
Carrot | 789 | C456 | MT
Celery | 891 | E891 | SW
Fiddle
https://www.db-fiddle.com/f/ipmwJwpru4ZmroGQJwpdjP/0
Food table
Name | NUM | ID
-------------------
Apple | 123 | A234
Orange | 456 | B789
Carrot | 789 | C456
Cherry | 234 | D123
Celery | 891 | E891
Number_type table
NUM | TYPE
----------
123 | SR
123 | AD
456 | SW
567 | SP
891 | SW
ID_type table
ID | TYPE
-----------
A234 | SW
B789 | AD
C456 | SW
D123 | SP
C456 | AD
E891 | FJ
Expected Results
Name | NUM | ID | TYPE
--------------------------
Apple | 123 | A234 | MT
Orange | 456 | B789 | SW
Carrot | 789 | C456 | MT
Cherry | 234 | D123 | SP
Celery | 891 | E891 | SW
I am thinking of two left joins and conditional logic:
select
f.name,
f.num,
f.id,
case when coalesce(n.min_type, i.min_type) = coalesce(n.max_type, i.max_type)
then coalesce(n.min_type, i.min_type)
else 'MT'
end as type
from food f
left join (
select num, min(type) min_type, max(type) max_type
from number_type
group by num
) n on n.num = f.num
left join (
select id, min(type) min_type, max(type) max_type
from id_type
group by id
) i on i.id = f.id and n.num is null
where n.num is not null or i.id is not null
In your db fiddle, this produces:
| name | num | id | type |
| ------ | --- | ---- | ---- |
| Apple | 123 | A234 | MT |
| Cherry | 234 | D123 | SP |
| Orange | 456 | B789 | SW |
| Carrot | 789 | C456 | MT |
| Celery | 891 | E891 | SW |
Here is way to do this
select a.name
,a.num
,a.id
,case when count(distinct nt.type)>1 then
'MT'
when count(distinct it.type) > 1 then
'MT'
when max(nt.type) is not null then
max(nt.type)
when max(it.type) is not null then
max(it.type)
end as type_computed
from food a
left join num_type nt
on a.num=nt.num
left join id_type it
on it.id=a.id
group by a.name
,a.num
,a.id
+--------+-----+------+---------------+
| NAME | NUM | ID | type_computed |
+--------+-----+------+---------------+
| Apple | 123 | A234 | MT |
| Carrot | 789 | C456 | MT |
| Celery | 891 | E891 | SW |
| Cherry | 234 | D123 | SP |
| Orange | 456 | B789 | SW |
+--------+-----+------+---------------+

SQL MAX query using 3 tables

I'm having difficulty querying an SQL database.
| patient_id | episode_number | attend_practitioner | pract_assignment_date |
| ---------- | -------------- | ------------------- | --------------------- |
| 111 | 4 | 4444 | 01/05/2017 |
| 222 | 8 | 5555 | 03/17/2017 |
| 222 | 8 | 6666 | 03/20/2017 |
| 222 | 9 | 7777 | 04/10/2017 |
| 333 | 2 | 5555 | 10/08/2017 |
| 444 | 7 | 7777 | 08/09/2017 |
| patient_id | episode_number | backup_practitioner | date_of_assignment |
| ---------- | -------------- | ------------------- | ------------------ |
| 111 | 4 | | |
| 222 | 8 | 7777 | 03/17/2017 |
| 222 | 8 | 4444 | 05/18/2017 |
| 222 | 9 | | |
| 333 | 2 | 4444 | 10/08/2017 |
| 333 | 2 | 5555 | 10/19/2017 |
| patient_id | episode_number | admit_date |
| ---------- | -------------- | ---------- |
| 111 | 4 | 01/05/2017 |
| 222 | 8 | 03/17/2017 |
| 222 | 9 | 03/20/2017 |
| 333 | 2 | 10/08/2017 |
I'm looking for an SQL query where I can enter a staff_id and then have it return all the open episodes they are currently assigned to. Result:
| staff_id | patient_id | episode_number | admit_date | date_of_assignment |
| -------- | ---------- | -------------- | ---------- | ------------------ |
| 4444 | 111 | 4 | 01/05/2017 | 01/05/2017 |
| 4444 | 222 | 8 | 03/17/2017 | 05/18/2017 |
I don't understand how the SQL handles aliases in the query.
The SQL doesn't know what to do with SQL window functions such as OVER, LAG(), LEAD(), etc. So I'm using self joins along with the MAX() function. Maybe this is an older SAP SQL server.
I don't know whether capitalization in the SQL query is irrelevant.
This is a bit hard to work out from your question. I thin you need to most recent assignment for each patient/episode.
You could do this with a second sub-query using max, or you could use not exists as per below.
As you mentioned, it would be much easier with a row_number() and or CTE's, but this is bulk standard sql version.
select s.staff_id, e.patient_id, e.episode_number as episode_id, e.admit_date, s.date_of_assignment, c.last_date_of_service
from episode_history e
join (
select patient_id, episode_number, attend_practitioner as staff_id, pract_assignment_date as date_of_assignment
from history_attending_practitioner
union
select patient_id, episode_number, backup_practitioner as staff_id, date_of_assignment as date_of_assignment
from user_practitioner_assignment
where backup_practitioner is not null
) s on s.patient_id=e.patient_id and s.episode_number=e.episode_number
and not exists(select * from history_attending_practitioner a2 where a2.patient_id=s.patient_id and a2.episode_number=s.episode_number and a2.pract_assignment_date>s.date_of_assignment)
and not exists(select * from user_practitioner_assignment a3 where a3.patient_id=s.patient_id and a3.episode_number=s.episode_number and a3.date_of_assignment>s.date_of_assignment)
join view_episode_summary_current c on c.patient_id=e.patient_id and c.episode_number=e.episode_number
where e.discharge_date is null
After tweaking the query items, this is the SQL query version that returned the correct results:
SELECT
t1.staff_id
, t1.patient_id
, t3.admit_date
, t1.episode_number
, t1.date_of_assignment
FROM
/* select the most recent attending practitioner entry from table1 for the patient and episode */
(SELECT attending_practitioner AS staff_id, patient_id, episode_number, pract_assignment_date AS date_of_assignment
FROM table1 AS t1a
WHERE t1a.pract_assignment_date =
(SELECT MAX(pract_assignment_date)
FROM table1 AS t1b
WHERE t1b.patient_id = t1a.patient_id
AND t1b.episode_number = t1a.episode_number)
UNION
/* select the most recent practitioner entry from table2 for the patient and episode */
SELECT backup_practitioner AS staff_id, patient_id, episode_number, date_of_assignment
FROM table2 AS t2a
WHERE t2a.date_of_assignment =
(SELECT MAX(date_of_assignment)
FROM table2 AS t2b
WHERE t2b.patient_id = t2a.patient_id
AND t2b.episode_number = t2a.episode_number)
) AS t1
INNER JOIN
/* filter out closed episodes by using the table3 */
(SELECT patient_id AS patient_id2, episode_number AS episode_number2, admit_date
FROM table3) AS t3
ON t3.patient_id = t1.patient_id
AND t3.episode_number2 = t1.episode_number
WHERE t1.staff_id = '4444'

PostgreSQL Crosstab Select Query

Does any one know how to create crosstab queries in PostgreSQL?
For example I have two following tables:
TABLE A
| ID 1 | ID 2 | ID 3 |
|:-----------|------------:|:------------:|
| 00001 | 01 | 0001 |
| 00001 | 02 | 0001 |
| 00001 | 01 | 0002 |
TABLE B
| ID 1 | ID 2 | ID 3 | price | tax_rate |
|:-----------|------------:|:------------:|:------------:|:------------:|
| 00001 | 01 | 0001 |5000 | 8 |
| 00001 | 01 | 0001 |6000 | 10 |
I would like the query to return the following crosstab:
| ID 1 | ID 2 | ID 3 | price_8 | price_10 |
|:-----------|------------:|:------------:|:------------:|:------------:|
| 00001 | 01 | 0001 |5000 | 6000 |
| 00001 | 02 | 0001 |null | null |
| 00001 | 01 | 0002 |null | null |
Is this possible?
Try this -
SELECT * FROM crosstab(
'SELECT A.ID1, A.ID2, A.ID3, B.PRICE, B.TAX_RATE
FROM A
LEFT JOIN B
ON A.ID1 = B.ID1
AND A.ID2 = B.ID2
AND A.ID3 = B.ID3') AS
FINAL_RESULT (ID1 TEXT, ID2 TEXT, ID3 TEXT, PRICE_8 NUMERIC, PRICE_9 NUMERIC);
Here is a sample for your tables:
SELECT split_part(id, '.', 1) AS id1,
split_part(id, '.', 2) AS id2,
split_part(id, '.', 3) AS id3,
price_8, price_10
FROM crosstab(
'select id1||''.''||id2||''.''||id3 as id, cast(tax_rate as text) as taxRate, price
from (select * from Table1 natural left join Table2
order by 1,2,3) t'
)
AS ct (
id text,
price_8 int,
price_10 int
);

Select values of a column into one row - SQL Server

I want to select in one row the value of a column that appears in multiple rows, I have the table Solution:
| StudentID | SolutionDate | SolutionTime | SongID |
----------------------------------------------------
| 0824616 | 2015-09-20 | 00:07:00 | 01 |
| 0824616 | 2015-09-20 | 00:05:00 | 02 |
| 0824616 | 2015-09-21 | 00:07:40 | 01 |
| 0824616 | 2015-09-21 | 00:10:00 | 03 |
| 0824616 | 2015-09-23 | 00:04:30 | 03 |
| 0824616 | 2015-09-23 | 00:11:30 | 03 |
I want to group the records by StudentID and SongID.
The expected output is:
| StudentID | SongID | TimeA | TimeB | TimeC |
-------------------------------------------------------
| 0824616 | 01 | 00:07:00 | 00:07:40 | NULL |
| 0824616 | 02 | 00:05:00 | NULL | NULL |
| 0824616 | 03 | 00:10:00 | 00:04:30 | 00:11:30 |
There are 3 records by StudentID-SongID at the most. I'm using SQL Server 2012.
Try with window function first to number the rows and then use conditional aggregation:
;with cte as(select *, row_number() over(partition by studentid, songid
order by solutiondate, solutiontime) rn from tablename)
select studentid,
songid,
max(case when rn = 1 then solutiontime end) as timea,
max(case when rn = 2 then solutiontime end) as timeb,
max(case when rn = 3 then solutiontime end) as timec
from cte
group by studentid, songid

SQL Server pivot with "ties"

Here is my source data:
+-------+-------+-------+------+
| Categ | Nm | Value | Rnk |
+-------+-------+-------+------+
| A | Tom | 37 | 1 |
| A | Joe | 36 | 2 |
| A | Eddie | 35 | 3 |
| B | Seth | 28 | 1 |
| B | Ed | 25 | 2 |
| B | Billy | 22 | 3 |
| C | Julie | 42 | 1 |
| C | Jenny | 41 | 2 |
| C | April | 40 | 3 |
| C | Mary | 40 | 3 |
| C | Laura | 40 | 3 |
+-------+-------+-------+------+
And here is the output I would like to produce:
+------+--------+--------+-------+
| Rnk | A | B | C |
+------+--------+--------+-------+
| 1 | Tom | Seth | Julie |
| 2 | Joe | Ed | Jenny |
| 3 | Eddie | Billy | April |
| 3 | (null) | (null) | Mary |
| 3 | (null) | (null) | Laura |
+------+--------+--------+-------+
I have used the following approach (which I understand through other posts may be superior to actually using PIVOT)...and this gets me to where I see Julie/Jenny/April, but not Mary/Laura (obviously, since it is pulling the MIN in the event of a 'tie').
SELECT Rnk
, min(CASE WHEN Categ = 'A' THEN Nm END) as A
, min(CASE WHEN Categ = 'B' THEN Nm END) as B
, min(CASE WHEN Categ = 'C' THEN Nm END) as C
FROM Tbl
GROUP BY Rnk
How to get to my desired output?
Well, if you want multiple rows for each rank, you can't aggregate by rank, or at least by rank alone. So, calculate the rank-within-the-rank or as the following query calls it, the sub_rnk:
SELECT Rnk,
min(CASE WHEN Categ = 'A' THEN Nm END) as A,
min(CASE WHEN Categ = 'B' THEN Nm END) as B,
min(CASE WHEN Categ = 'C' THEN Nm END) as C
FROM (select t.*, row_number() over (partition by categ, rnk order by newid()) as sub_rnk
from Tbl t
) t
GROUP BY rnk, sub_rnk
ORDER BY rnk;