Access SQL - Is it possible to group by switch values? - sql

Using Access 2010, I am trying to group by switch values and currently having trouble working out the code. Basically, within the treatment field in my DB, I have values such as D1, D2, D3, E1, E2, E3. The first letter denotes a particular treatment type e.g. D = Treatment1, E = Treatment2. I am looking to group the data by 'Treatment1' and 'Treatment2' for example.
SELECT switch(LEFT(t1.[treatment],1)='D',"Treatment1",LEFT(t1.[treatment],1)='E',"Treatment2"), count(t1.[UniqueID]) AS Total_Population, count(t2.[date]) AS DateSent, format(count(t2.[date]) / count(t1.[UniqueID]),"0.00%") AS Percentage_Sent, COUNT(IIF(t1.[requirements]='1',1,)) AS requirements_population
FROM Main_table AS t1 LEFT JOIN (SELECT t2.[ID], t2.[date] FROM Main_table AS t2 WHERE t2.date Not Like ('NA')) AS t2 ON t1.[ID] = t2.[ID]
GROUP BY [treatment]
Expected output is for example, Treatment1 - x amount, Treatment2 - y amount. However at present I get multiple rows of both Treatment1 & Treatment2 as the data behind those expressions is not unique (i.e. D1, D2, D3, E1, E2, E3).

Change to:
GROUP BY LEFT(t1.[treatment], 1)
so you group by the 1st letter of t1.[treatment] and not t1.[treatment]

Related

proc sql join in SAS that is closest to a date

How can I do a one-to-many join between two datasets with proc sql in SAS to obtain the record in Dataset B is closest to a value in Dataset A?
Dataset A
#Patient #Date of Dose
001 2020-02-01
Dataset B
# Patient # Lab Test #Date of Test # Value
001 Test 1 2020-01-17 6
001 Test 1 2020-01-29 10
I want to do the join to select the second record in Dataset B, the record with a "Date of Test" that is the closest (less than or equal to) to the "Date of Dose" in the first dataset.
I want to do the join to select the [..] record in Dataset B [...] with a "Date of Test" that is the closest (less than or equal to) to the "Date of Dose" in the first dataset.
You could use outer appy - if sas supports that:
select a.*, b.*
from a
outer apply(
select top 1 b.*
from b
where b.patient = a.patient and b.date_of_test <= a.date_of_dose
order by b.date_of_test desc
) b
Another solution is to join with a not exists condition:
select a.*, b.*
from a
left join b
on b.patient = a.patient
and b.date_of_test <= a.date_of_dose
and not exists (
select 1
from b b1
where
b1.patient = a.patient
and b1.date_of_test <= a.date_of_dose
and b1.date_of_test > b.date_of_test
)
Calculate the absolute difference between both dates and select the minimum date with a having clause. You'll need to do additional logic, such as distinct, to remove any duplicates.
proc sql noprint;
select t1.patient
, t1.date_of_dose
, abs(t1.date - t2.date) as date_dif
from dataset_A as t1
LEFT JOIN
dataset_B as t2
ON t1.patient = t2.patient
where t1.date <= t2.date
group by t1.patient
having calculated date_dif = min(calculated date_dif)
;
quit;
try this:
SELECT TOP 1 *
FROM (
SELECT DSA.Patient
,DSA.Date_Of_Dose
,DSB.Date_Of_Test
,DATEDIFF(Day, DSA.Date_Of_Dose, DSA.Date_Of_Dose) Diff
FROM DataSetA DSA
JOIN DataSetB DSB ON DSA.Patient = DSB.Patient
) Data
WHERE ABS(Diff) = MIN(ABS(Diff));
Sorry, I got no way to know if this is working 'cause I'm not at home. I hope it helps you.
I want to do the join to select the second record in Dataset B, the record with a "Date of Test" that is the closest (less than or equal to) to the "Date of Dose" in the first dataset.
I would recommend cross-joining Date of Test and Date of Dose, and calculate absolute difference between the dates using intck() function, and leave the minimal value.

SqlServer - search if a list of values is fully contained on table

I have a sql table and a list of values to search.
if at least all the elements of the table are contained in the list, then I must return the Ticket Id (it means that I will update this record). Otherwise, I will return null (it means that it will be a new registration).
For example
Use cases:
If I search for this elements: C1, C3, C6, it will be an update and I will get ticketid 1
If I search for this elements: C8, C3, C6, C10, it will be a create and I will get null as return value
A list of values is a Predefined-Type with a column, in this case, #ElementsToSearch with a column Value
SELECT T.Id
FROM
Ticket t
INNER JOIN
TicketValue TL ON TL.TicketId = T.Id
LEFT OUTER JOIN
#ElementsToSearch ES ON ES.Value = TL.Value
WHERE
ES.Value is null
thank you
Whatever you want to return just interchange null and 1
declare #ElementsToSearch as Table(value varchar(10))
insert into #ElementsToSearch values('C1'),('C2'),('C3')
SELECT
CASE WHEN (COUNT(CASE WHEN ES.value IS NULL then 1 end)>0) then NULL else T.id end as output
FROM
Ticket t
INNER JOIN
TicketValue TL ON TL.TicketId = T.Id
LEFT OUTER JOIN
#ElementsToSearch ES ON ES.Value = TL.Value
group by T.id

Group by on two tables and perform Left join on outcome VBA ADODB SQL Query

I want to perform Group BY on two csv files and then perform Left Join on the outcome of both tables through VBA ADO Query in Excel. My end motive is to print the recordset.
Here is what I have done so far.
SELECT * FROM (
SELECT f1.[c3],
f1.[c4],
f1.[c5],
f1.[c6],
Sum(f1.[c8]) AS SUMDATA
FROM test1.csv F1
GROUP BY f1.[c3],
f1.[c4],
f1.[c5],
f1.[c6]) AS f3
LEFT JOIN SELECT * FROM (
SELECT f2.[c3],
f2.[c4],
f2.[c5],
f2.[c6],
Sum(f2.[c8]) AS SUMDATA
FROM test2.csv f2
GROUP BY f2.[c3],
f2.[c4],
f2.[c5],
f2.[c6]) AS f4
on f3.[c3]+ f3.[c4]+ f3.[c5]+ f3.[c6] = f4.[c3]+ f4.[c4]+ f4.[c5]+ f4.[c6]
WHERE f3.[SUMDATA] <> f4.[SUMDATA]
This shows a syntax error. How to implement this? Any help is much appreciated. TIA.
An update -
I manage to implement 1 LEFT JOIN and 2 GROUP BYs between 2 tables. As per the request, here are few details regarding my dataset.
It consists of fields - c1, c2 .... c8.
c8 is my target field.
My expected output - I do not need c7, c1 and c2 in output sheet. The info of c7, c1 and c2 is irrelevant. I need to do 5 things with my data.
Group Sum the c8 field based on c3, c4, c5 and c6 fields in CSV file 1 and store target field as SUMDATA
Group Sum the c8 field based on c3, c4, c5 and c6 fields in CSV file 2 and store target field as SUMDATA
Find the mismatched SUMDATA field entries between CSV1 and CSV2 (I used LEFT JOIN for this on concatenated c3, c4, c5, c6 fields)
Find the entries which are present in CSV1 but not in CSV2
Find the entries which are present in CSV2 but not in CSV1
Currently, I manage to write the code that works till step 3. I need to store the grouped tables temporarily which I got from Step 1 and 2, to perform the steps 4 and 5 which can be done through 2 more UNION, LEFT JOINs, and WHERE combination. This is where I am stuck right now.
This isn't really an answer but the formatting is important for readability.
It looks like there's a lot wrong with your SQL.
The syntax should look like this (assuming querying a csv works like you are thinking):
SELECT SUB1.Field1,
SUB1.AggField AS Agg1,
SUB2.AggField AS Agg2
FROM (SELECT Field1,
MAX(Field2) Agg_Field
FROM Table1 T1
GROUP
BY Field1
) SUB1
LEFT
JOIN (SELECT Field1,
MAX(Field2) Agg_Field
FROM Table1 T2
GROUP
BY Field1
) SUB2
ON SUB1.Field1 = SUB2.Field1
WHERE SUB1.AggField <> SUB2.AggField;
Also, you are missing a comma here: F1.[c5] F1.[c6] in the first chunk.
Try fixing the SQL syntax like this and see where that gets you.

How to get all Contract no against Leads in oracle sql query?

I need to create a sql query for below scenario:
Table name is remark
Columns are contractno and leadid.
1 contractno can have multiple leadid.
similarly,
1 leadid can assigned to multiple contractno.
Lets assume:
C1 --> L1
C2 --> L1, L2
C3 --> L2
I will get only one contractno i.e. C1 as parameter.
Now I have to find all Contracts against C1 through leadid.
Please help me out how I can achieve this.
Thank you.
SELECT r1.contractno
FROM remark r1
JOIN remark r2
ON r1.leadid = r2.leadid
WHERE r2.contractno = 'C1'
AND r1.contractno <> 'C1'
This assume your table has this format:
contractno leadid
C1 L1
C2 L1
C2 L2
C3 L1
If you dont, then you need to split the csv value into rows first:
Turning a Comma Separated string into individual rows
You can use a LISTAGG if you have to group list of contracts. Here too it is assumed that your table has linear format and not comma separated leadids
WITH cn
AS (SELECT DISTINCT leadid
FROM remark
WHERE contractno = 'C1')
SELECT Listagg(r.contractno, ',')
within GROUP (ORDER BY ROWNUM) contractno_C1
FROM remark r
join cn
ON r.leadid = cn.leadid
WHERE r.contractno <> 'C1'
GROUP BY cn.leadid;
http://sqlfiddle.com/#!4/54e48/1/0

How to select a particular partition in Postgres when using partition by clause

I have a query with the following structure -
select a.a1,b.b1,c.c1,d.d1,
count(e.e1) over (partition by e.e2)
from a join b
on a.aid = b.bid
join c
on b.bid = c.cid
join e
......many other joins;
The problem is that I want to do something like
count(e.e1) over (partition by e.e2 where e.e2 = 'mouse')
I mean I want to partition by the e2 column but consider one of the partitions.
For example, if e2 columns had the following values - "mouse", "cat" and "dog". Then the above query would give an output resembling the following -
a11 b11 c11 d11 4 -> record for "mouse"
a11 b11 c11 d11 5 -> record for "cat"
a11 b11 c11 d11 7 -> record for "dog"
Now, I don't want the records for "cat" and "dog". I only want for "mouse".
Any suggestions?
I think you want conditional aggregation:
select sum(case when e2 = 'mouse' then 1 else 0 end) over ()
This puts the number of "mouse"s on each row in the result set.
EDIT:
If it is based on the column, then you just want:
select count(*) over (partition by e2)