Oracle SQL Select Where Column equals more than one value - sql

Pretty straight forward. What is wrong with this statement.
SELECT DISTINCT CUST_FNAME "FIRST NAME", CUST_LNAME "LAST NAME", POS_TIME "TIME", POS_DATE "DATE" FROM POS, CUSTOMER
WHERE CUST_NUM = POS_CUST_NUM AND POS_ITEMID = 1 AND POS_ITEMID = 2;

I think you might want customers who are associated with BOTH items 1 and 2. In that case you can use the following:
select x.*, pos_time, pos_date
from (SELECT CUST_NUM, CUST_FNAME, CUST_LNAME
FROM POS
join CUSTOMER
on CUST_NUM = POS_CUST_NUM
where POS_ITEMID = 1
intersect
SELECT CUST_NUM, CUST_FNAME, CUST_LNAME
FROM POS
join CUSTOMER
on CUST_NUM = POS_CUST_NUM
where POS_ITEMID = 2) x
join pos
on x.cust_num = pos.pos_cust_num
where pos_itemid in (1, 2)

Not sure, but this might be a little more efficient than the intersect that Brian did above. Also, I don't have access to a database right now, so my syntax may be slightly off.
select CUST_NUM, CUST_FNAME, CUST_LNAME, pos_time, pos_date
from CUSTOMER c1,POS p1
where c1.cust_num = p1.pos_cust_num
and p1.pos_itemid=1
and exists (select 'x' from
pos p2
where p2.pos_cust_num=p1.pos_cust_num
and p2.pos_itemid=2)
basically, give me everyone where the ordered itemid 1 and where a record exists where the same customer ordered itemid 2.

Related

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);

Function to split value between columns in access

I have the following table:
And I need to split the value column into two columns based on the value of the status column, also add a difference between the two. Like This:
I was able to split it by using two separate queries, but when I merge them together I get duplicate values, even If I use the Sum and group by the costumer.
You can sue conditional aggregation:
select customer,
sum(iif(status = 'debt', value, 0)) as debt,
sum(iif(status = 'pay', value, 0)) as pay
(sum(iif(status = 'debt', value, 0)) -
sum(iif(status = 'pay', value, 0))
) as diff
from t
group by customer;
Try this please
tb1: Customer, value, status
select d.Customer, d.value as debt, IIf(p.value Is Null, 0, p.value) as pay, d.value - IIf(p.value Is Null, 0, p.value) as diff
from
(select Customer, value from tb1 where status = 'debt')d
left join
(select Customer, value from tb1 where status = 'pay')p on d.Customer = p.Customer
With a LEFT self join:
select t.Customer,
t.[value] as debt, tt.[value] as pay, t.[value] - Nz(tt.[value]) as diff
from tablename t left join tablename tt
on tt.customer = t.customer and t.[status] <> tt.[status]
where t.[status] = 'debt'
Results:
Customer debt pay diff
Fernando 445 445 0
Marcelo 332 123 209
Adriana 889 889

Distinct keyword not fetching results in Oracle

I have the following query where I unique records for patient_id, meaning patient_id should not be duplicate. Each time I try executing the query, seems like the DB hangs or it takes hours to execute, I'm not sure. I need my records to load quickly. Any quick resolution will be highly appreciated.
SELECT DISTINCT a.patient_id,
a.study_id,
a.procstep_id,
a.formdata_seq,
0,
(SELECT MAX(audit_id)
FROM audit_info
WHERE patient_id =a.patient_id
AND study_id = a.study_id
AND procstep_id = a.procstep_id
AND formdata_seq = a.formdata_seq
) AS data_session_id
FROM frm_rg_ps_rg a,
PATIENT_STUDY_STEP pss
WHERE ((SELECT COUNT(*)
FROM frm_rg_ps_rg b
WHERE a.patient_id = b.patient_id
AND a.formdata_seq = b.formdata_seq
AND a.psdate IS NOT NULL
AND b.psdate IS NOT NULL
AND a.psresult IS NOT NULL
AND b.psresult IS NOT NULL) = 1)
OR NOT EXISTS
(SELECT *
FROM frm_rg_ps_rg c
WHERE a.psdate IS NOT NULL
AND c.psdate IS NOT NULL
AND a.psresult IS NOT NULL
AND c.psresult IS NOT NULL
AND a.patient_id = c.patient_id
AND a.formdata_seq = c.formdata_seq
AND a.elemdata_seq! =c.elemdata_seq
AND a.psresult != c.psresult
AND ((SELECT (a.psdate - c.psdate) FROM dual)>=7
OR (SELECT (a.psdate - c.psdate) FROM dual) <=-7)
)
AND a.psresult IS NOT NULL
AND a.psdate IS NOT NULL;
For start, you have a cartesian product with PATIENT_STUDY_STEP (pss).
It is not connected to anything.
select *
from (select t.*
,count (*) over (partition by patient_id) as cnt
from frm_rg_ps_rg t
) t
where cnt = 1
;

SQL: break column into multiple columns by cell value

I'm trying to build a module in VBA that will query 2 data sources and left join them on the common field of "Name". The problem is that the data are grained differently. The set I'm trying to change currently looks like this:
And I'm trying to make it look like this:
So that I can left join it with a query from my second dataset, which is grained by "name" rather than "item value".
FWIW, here's what the query I'm currently trying to run looks like. I'm using an implicit join to get "current value" and "past value" for each "name", but none of this refers to dataset 2:
with set1 as (SELECT NAME, ITEM_CODE, ITEM_VALUE_NUMBER as CURRENT_VALUE FROM [...] WHERE [...]),
with set2 as (SELECT NAME, ITEM_CODE, ITEM_VALUE_NUMBER as PAST_VALUE FROM [...] WHERE [...]),
SELECT set1.NAME [ITEM_1], [ITEM_2], [ITEM_3] from
(SELECT set1.NAME, set1.CURRENT_VALUE, set2.PAST_VALUE FROM set1, set2 WHERE set1.NAME=set2.NAME and set1.ITEM_CODE=set2.ITEM_CODE) AS SourceTable
PIVOT (max(CURRENT_VALUE) for ITEM_CODE in [ITEM_1], [ITEM_2], [ITEM_3]) AS PivotTable;
Thanks in advance for any guidance you can offer!
So, you have a couple options. First is trying to reword the pivot to get the results you want, which makes for a more complicated query than required. You can do this in the following way if you wish:
SELECT Name
, MAX(C1) Item1CurrentValue
, MAX(P1) Item1PastValue
, MAX(C2) Item2CurrentValue
, MAX(P2) Item2PastValue
, MAX(C3) Item3CurrentValue
, MAX(P3) Item3PastValue
FROM (
SELECT set1.Name
, 'C' + CAST(set1.ItemCode AS VARCHAR(255)) ItemCode1
, CurVal
, 'P' + CAST(set2.ItemCode AS VARCHAR(255)) ItemCode2
, PastVal
FROM (SELECT Name, ItemCode, ITEM_VALUE_NUMBER CurVal FROM myFirstQuery) set1
JOIN (SELECT Name, ItemCode, ITEM_VALUE_NUMBER PastVal FROM mySecondQuery) set2 ON set1.Name = set2.Name AND set1.ItemCode = set2.ItemCode) T
PIVOT (MAX(CurVal) FOR ItemCode1 IN (C1, C2, C3)) P1
PIVOT (MAX(PastVal) FOR ItemCode2 IN (P1, P2, P3)) P2
GROUP BY Name;
I don't really think CTEs make the query more readable so I just removed them, but you could use the CTEs in a similar fashion if you wish.
The better (and easier to understand, in my opinion) way is to just use conditional aggregation, like such:
SELECT Name
, MAX(CASE WHEN ItemCode = 1 THEN CurVal END) Item1CurrentValue
, MAX(CASE WHEN ItemCode = 1 THEN PastVal END) Item1PastValue
, MAX(CASE WHEN ItemCode = 2 THEN CurVal END) Item2CurrentValue
, MAX(CASE WHEN ItemCode = 2 THEN PastVal END) Item2PastValue
, MAX(CASE WHEN ItemCode = 3 THEN CurVal END) Item3CurrentValue
, MAX(CASE WHEN ItemCode = 3 THEN PastVal END) Item3PastValue
FROM (
SELECT set1.Name
, set1.ItemCode
, CurVal
, PastVal
FROM (SELECT Name, ItemCode, ITEM_VALUE_NUMBER CurVal FROM myFirstQuery) set1
JOIN (SELECT Name, ItemCode, ITEM_VALUE_NUMBER PastVal FROM mySecondQuery) set2 ON set1.Name = set2.Name AND set1.ItemCode = set2.ItemCode) T
GROUP BY Name;

Fastest way to check if the the most recent result for a patient has a certain value

Mssql < 2005
I have a complex database with lots of tables, but for now only the patient table and the measurements table matter.
What I need is the number of patient where the most recent value of 'code' matches a certain value. Also, datemeasurement has to be after '2012-04-01'. I have fixed this in two different ways:
SELECT
COUNT(P.patid)
FROM T_Patients P
WHERE P.patid IN (SELECT patid
FROM T_Measurements M WHERE (M.code ='xxxx' AND result= 'xx')
AND datemeasurement =
(SELECT MAX(datemeasurement) FROM T_Measurements
WHERE datemeasurement > '2012-01-04' AND patid = M.patid
GROUP BY patid
GROUP by patid)
AND:
SELECT
COUNT(P.patid)
FROM T_Patient P
WHERE 1 = (SELECT TOP 1 case when result = 'xx' then 1 else 0 end
FROM T_Measurements M
WHERE (M.code ='xxxx') AND datemeasurement > '2012-01-04' AND patid = P.patid
ORDER by datemeasurement DESC
)
This works just fine, but it makes the query incredibly slow because it has to join the outer table on the subquery (if you know what I mean). The query takes 10 seconds without the most recent check, and 3 minutes with the most recent check.
I'm pretty sure this can be done a lot more efficient, so please enlighten me if you will :).
I tried implementing HAVING datemeasurment=MAX(datemeasurement) but that keeps throwing errors at me.
So my approach would be to write a query just getting all the last patient results since 01-04-2012, and then filtering that for your codes and results. So something like
select
count(1)
from
T_Measurements M
inner join (
SELECT PATID, MAX(datemeasurement) as lastMeasuredDate from
T_Measurements M
where datemeasurement > '01-04-2012'
group by patID
) lastMeasurements
on lastMeasurements.lastmeasuredDate = M.datemeasurement
and lastMeasurements.PatID = M.PatID
where
M.Code = 'Xxxx' and M.result = 'XX'
The fastest way may be to use row_number():
SELECT COUNT(m.patid)
from (select m.*,
ROW_NUMBER() over (partition by patid order by datemeasurement desc) as seqnum
FROM T_Measurements m
where datemeasurement > '2012-01-04'
) m
where seqnum = 1 and code = 'XXX' and result = 'xx'
Row_number() enumerates the records for each patient, so the most recent gets a value of 1. The result is just a selection.