How to use 1 SQL query related to date and time in order to compare value difference - sql

SELECT c.treatment_category, a.treatment_id, MAX(a.counts - b.counts) AS ReviewDifference
FROM
(SELECT treatment_id, COUNT(treatment_id) AS counts
FROM review
WHERE DATE(review.created) BETWEEN DATE(TIMESTAMP'2016-01-01 00:00:00.0') AND DATE(TIMESTAMP'2016-12-31 23:59:59.999')
GROUP BY treatment_id) a
LEFT JOIN
(SELECT treatment_id, COUNT(treatment_id)
FROM review
WHERE DATE(review.created) BETWEEN DATE(TIMESTAMP'2015-01-01 00:00:00.0') AND DATE(TIMESTAMP'2015-12-31 23:59:59.999')
GROUP BY treatment_id) b
ON a = b
LEFT JOIN
(SELECT t.treatment_category AS category, r.treatment_id AS number
FROM treatment t
LEFT JOIN review r
ON t.treatment_id = r.treatment_id
GROUP BY category, number) c
ON b.treatment_id = c.number
GROUP BY a.treatment_id, c.treatment_category
ORDER BY ReviewDifference DESC
LIMIT 1;
I need some hints or simpler query on how to do this question since it is related to date and time. Thank you.
What treatment category has seen the biggest increase in reviews from 2015 to 2016?
Please see below for the tables.
I have provided my code snippet and I would like to find a simpler and cleaner way on writing the code.

SELECT t.treatment_id, t.treatment_name,
COUNT( CASE WHEN YEAR(created) = 2016 THEN r.review_id END)
- COUNT( CASE WHEN YEAR(created) = 2015 THEN r.review_id END) as review_count
FROM treatments t
JOIN reviews r
ON t.treatment_id = r.treatment_id
GROUP BY t.treatment_id, t.treatment_name,
ORDER BY review_count DESC

Related

Trying to count number of complaint, cause, corrections

I am trying to create a query with the following fields, that counts the number of Complaints, causes, and corrections show up in the data.
My current error: Select non-aggregate values must be part of the associated group.
I am very new to SQL queries, and am not sure what else I'm missing. All I've done is merged to queries, and seem to be missing something.
select L.Case_ID,
L.Case_Line_ID,
A.Dealer_ID,
M.DealerCode,
H.DealerName,
substr(L.Estimate_Created_At,1,7) as CaseMonth,
count(distinct L.Complaint) as Complaint,
count(distinct C.Cause) as Cause,
count(distinct C.Correction) as Correction
from Decisiv_Tables_Prod.Stg_Decisiv_LineItems L
join Decisiv_Tables_Prod.Stg_Decisiv_Cases A on L.Case_ID = A.Case_ID
join Decisiv_Tables_Prod.Rpt_DecisivDealerMap M on A.Dealer_ID = M.DecisivDealerID
and cast(substr(L.Estimate_Created_At,1,10) as date format 'YYYY-MM-DD') between M.EffectiveStartDate and coalesce(M.EffectiveEndDate, cast('2099-12-31' as date format 'YYYY-MM-DD'))
join Decisiv_Tables_Prod.Rpt_DealerDirectoryHierarchy H on M.DealerCode = H.DealerCode
join Decisiv_Tables_Prod.Stg_Decisiv_LineItems_Clobs C on C.Case_ID = L.Case_ID
and C.Case_Line_ID = L.Case_Line_ID
group by 1,2,3,4,5
Looking to get a table with the following data example:
Dealer ID, Dealer Code, Dealer Name, Case Month, Count of Case_ID, Count of Case_Line_ID, Count of Complaint, Count of Cause, Count of Correction
You have six unaggregated columns:
select L.Case_ID,
L.Case_Line_ID,
A.Dealer_ID,
M.DealerCode,
H.DealerName,
substr(L.Estimate_Created_At,1,7) as CaseMonth,
These should all be in the group by:
group by L.Case_ID, L.Case_Line_ID, A.Dealer_ID,
M.DealerCode, H.DealerName,
substr(L.Estimate_Created_At,1,7) as CaseMonth
As Gordon wrote, the GROUP BY list doesn't match your Select, you need to either remove both Case_ID & Case_Line_ID or aggregate them:
SELECT
A.Dealer_ID,
M.DealerCode,
H.DealerName,
Substr(L.Estimate_Created_At,1,7) AS CaseMonth,
Count(L.Case_ID), -- distinct ?
Count(L.Case_Line_ID), -- distinct ?
Count(DISTINCT L.Complaint) AS Complaint,
Count(DISTINCT C.Cause) AS Cause,
Count(DISTINCT C.Correction) AS Correction
FROM Decisiv_Tables_Prod.Stg_Decisiv_LineItems AS L
JOIN Decisiv_Tables_Prod.Stg_Decisiv_Cases AS A
ON L.Case_ID = A.Case_ID
JOIN Decisiv_Tables_Prod.Rpt_DecisivDealerMap AS M
ON A.Dealer_ID = M.DecisivDealerID
AND Cast(Substr(L.Estimate_Created_At,1,10) AS DATE FORMAT 'YYYY-MM-DD') BETWEEN M.EffectiveStartDate AND Coalesce(M.EffectiveEndDate, DATE '2099-12-31')
JOIN Decisiv_Tables_Prod.Rpt_DealerDirectoryHierarchy AS H
ON M.DealerCode = H.DealerCode
JOIN Decisiv_Tables_Prod.Stg_Decisiv_LineItems_Clobs AS C
ON C.Case_ID = L.Case_ID
AND C.Case_Line_ID = L.Case_Line_ID
GROUP BY
A.Dealer_ID,
M.DealerCode,
H.DealerName,
CaseMonth
I simplified cast('2099-12-31' as date format 'YYYY-MM-DD') to DATE '2099-12-31' and used the column names/aliases in Group By (recommended over 1,2,3,4 in production code).
As Distinct is quite expensive check if you actually need to add it to those counts.

How to find highest count of result set using multiple tables in SQL (Oracle)

I have four tables. Here are the skeletons...
ACADEMIC_TBL
academic_id
academic_name
AFFILIATION_TBL
academic_id*
institution_id*
joined_date
leave_date
INSTITUTION_TBL
institution_id
institution_name
REVIEW_TBL
academic_id*
institution_id*
date_posted
review_score
Using these tables I need to find the academic (displaying their name, not ID) with the highest number of reviews and the institution name (not ID) they are currently affiliated with. I imagine this will need to be done using multiple sub-select scripts but I'm having trouble figuring out how to structure it.
this will work:
SELECT at.academic_name,
it.institution_name,
Max(rt.review_score),
from academic_tbl at,
affiliation_tbl afft,
institution_tbl it,
review_tbl rt
WHERE AT.academic_id=afft.academic_id
AND afft.institution_id=it.institution_id
AND afft.academic_id=rt.academic_id
GROUP BY at.academia_name,it.instituton_id
You need an aggregated query that JOINs all 4 tables to count how many reviews were performed by each academic.
Query :
SELECT
inst.institution_name,
aca.academic_name,
COUNT(*)
FROM
academic_tbl aca
INNER JOIN affiliation_tbl aff ON aff.academic_id = aca.academic_id
INNER JOIN institution_tbl inst ON inst.institution_id = aff.institution_id
INNER JOIN review_tbl rev ON rev.academic_id = aca.academic_id AND rev.institution_id = aff.institution_id
GROUP BY
inst.institution_name,
aca.academic_name,
inst.institution_id,
aca.academic_id
NB :
added the academic and institution id to the GROUP BY clause to prevent potential academics or institutions having the same name from being (wrongly) grouped together
if the same academic performed reviews for different institutions, then you will find one row for each academic / institution couple, which, if I understood you right, is what you want
Try this one:
select
inst.institution_name
, aca.academic_name
from
academic_tbl aca
, institution_tbl inst
, affiliation_tbl aff
, review_tbl rev
, (
select
max(rt.review_score) max_score
from
review_tbl rt
, affiliation_tbl aff_inn
where
rt.date_posted >= aff_inn.join_date
and rt.date_posted <= aff_inn.leave_date
and rt.academic_id = aff_inn.academic_id
and rt.institution_id = aff_inn.institution_id
)
agg
where
aca.academic_id = inst.academic_id
and inst.institution_id = aff.institution_id
and aff.institution_id = rev.institution_id
and aff.academic_id = rev.academic_id
and rev.date_posted >= aff.join_date
and rev.date_posted <= aff.leave_date
and rev.review_score = agg.max_score
;
It might return more than one academic, if there are more with the same score (maximum one).

Show records where team assignment = 1

by changing the below TeamRecords = 1 to = another number finds the rows with the amount I change to, its only sometimes its counting one too many which is odd. When a new Incident is created it has a unique number and every time a new assignment is added from the Task table it adds another row of the IncidentNumber, so you could have duplicate Incident number rows which I've remove with the seq = 1 below. When a new assignment is created it creates a new CreateddateTime in the Task table so for example you could do a Max(t.[CreatedDateTime] to find the last assignment of any IncidentNumber. So, the TeamRecords = 1 is what I need to find all records for that specific team where there is only 1 assignment for that team.
Does that help any?
Here is what I have so far...
Use TEST
Go
WITH RankResult AS
(
SELECT i.[IncidentNumber],
i.[CreatedDateTime],
i.[ResolutionDateAndTime],
i.[Priority],
i.[Status],
i.[ClientName],
i.[ClientSite],
t.[OwnerTeam],
t.[Owner],
row_number() over( partition by i.RecID
order by t.CreatedDateTime desc, t.OwnerTeam ) seq,
TeamRecords = COUNT(*) OVER(PARTITION BY t.ParentLink_RecID)
FROM Incident as i
Inner JOIN Task as t
ON i.RecID = t.ParentLink_RecID
WHERE t.OwnerTeam = 'Infrastructure Services'
AND i.CreatedDateTime >= '20121001'
AND i.CreatedDateTime <= '20131001'
)
SELECT DISTINCT
[IncidentNumber],
[CreatedDateTime],
[ResolutionDateAndTime],
[Priority],
[Status],
[ClientName],
[ClientSite],
[OwnerTeam],
[Owner]
FROM RankResult
Where TeamRecords = 1
And Seq = 1
Order By IncidentNumber Asc
GO
Using ROW_NUMBER means you will return the first assignment per team, not necessarily the teams with only one assignment. To do this you can use COUNT(*) OVER():
WITH RankResult AS
(
SELECT i.[IncidentNumber],
i.[CreatedDateTime],
i.[ResolutionDateAndTime],
i.[Priority],
i.[Status],
i.[ClientName],
i.[ClientSite],
t.[OwnerTeam],
t.[Owner],
TeamRecords = COUNT(*) OVER(PARTITION BY i.RecID)
FROM Incident as i
INNER JOIN Task as t
ON i.RecID = t.ParentLink_RecID
WHERE t.OwnerTeam = 'Info Services'
AND i.CreatedDateTime >= '20121001'
AND i.CreatedDateTime <= '20131001'
)
SELECT DISTINCT
[IncidentNumber],
[CreatedDateTime],
[ResolutionDateAndTime],
[Priority],
[Status],
[ClientName],
[ClientSite],
[OwnerTeam],
[Owner]
FROM RankResult
WHERE TeamRecords = 1;
2 things to note that I have changed in addition to the analytic function. Firstly I have changed your dates to the culture independant format yyyyMMdd, yyyy-MM-dd can still be ambiguous, so 2013-01-02 could be the 1st Feb or the 2nd Jan depending on your server/session settings. Secondly, Your where cluase was turning your join into an INNER JOIN anyway, so I just made it an INNER JOIN:
FROM Incident as i
LEFT JOIN Task as t
ON i.RecID = t.ParentLink_RecID
WHERE t.OwnerTeam = 'Info Services'
AND i.CreatedDateTime >= '20121001'
Here, if there is no match in Task then OwnerTeam will be NULL and NULL = 'Info Services' evaluates to false, so you will never return any rows with no match in Task thus making it an INNER JOIN). If you did in fact want a LEFT JOIN then you need to move this clause to the JOIN:
FROM Incident as i
LEFT JOIN Task as t
ON i.RecID = t.ParentLink_RecID
AND t.OwnerTeam = 'Info Services'
WHERE i.CreatedDateTime >= '20121001'
You can always use a simple subquery which groups across the relevant columns, counts them, filters where the count is 1, then joins it back to the main table to select the appropriate rows:
SELECT Incident.*
FROM (
SELECT OwnerTeam
FROM Incident AS Inc1
GROUP BY OwnerTeam
HAVING COUNT( * ) = 1
) AS Team
, Incident
WHERE Incident.OwnerTeam = Team.OwnerTeam
(Without more information, though, it's difficult to say if this will work for you.)

joining no of reports in oracle

Hi I want to generate the report which will contain following things:
Daily report by country/destination against counts.
Eg.
No of contributions
No videos
No of experiences
Based on count yesterday, total for week, total for year for each destination.
I have written following query to count total for week.
select a.name, count(e.id),count(uc.id),count(v.id)
from accommodation a, user_contribution uc,experience_video ev, video v,
(select id "ID",user_contribution_id,accommodation_id,case
when modified_on is null then trunc(created_on)
else trunc(modified_on) end last_modified from experience)e
where
e.last_modified between trunc(sysdate)-7 and trunc(sysdate) and
e.accommodation_id = a.id and
e.user_contribution_id = uc.id and
e.id = ev.experience_id and
v.id = ev.video_id
group by a.name
union
select l.name, count(ex.id),count(uc.id),count(v.id),count(r.id)
from location l, user_contribution uc,experience_video ev, video v,
(select id "ID",user_contribution_id,location_id,case
when modified_on is null then trunc(created_on)
else trunc(modified_on) end last_modified from experience)ex
where
ex.last_modified between trunc(sysdate)-7 and
trunc(sysdate) and
l.id = ex.location_id and
ex.user_contribution_id = uc.id and
ex.id = ev.experience_id and
v.id = ev.video_id
group by l.name;
I can similarly write the query to extract weekly and yearly count.
basically I want all counts in one row for each destination.
Is there any better way of writing this query?
Would appreciate your help.

How get specific rows in grouped result

i need to group some data but because there are 4 store images , sql query return 4 result for every store. How can i get only one for a store by using sql query ?
select s.name,si.SHOP_IMG_PATH,count(*) amount from stab t
inner join shop s on (s.shop_id = t.shop_id)
inner join SHOP_IMG si on (s.shop_id= si.SHOP_ID)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name,si.SHOP_IMG_PATH
order by 3 desc,1 asc
As you see below image there a re 4 images so query can give random image
You are grouping by s.name, si.SHOP_IMG_PATH it will consider all possible combination of s.name, si.SHOP_IMG_PATH as separate you need to keep group by only s.name
Try this
SELECT a.NAME, a.PATH, a.AMOUNT
FROM (select
s.name AS 'NAME', si.SHOP_IMG_PATH AS 'PATH', count(*) AS 'AMOUNT',
ROW_NUMBER() OVER(PARTITION BY s.name
ORDER BY type si.SHOP_IMG_PATH) AS rk
from
stab t
inner join shop s on (s.shop_id = t.shop_id)
inner join SHOP_IMG si on (s.shop_id= si.SHOP_ID)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name
order by 3 desc,1 asc) a
WHERE a.rk = 1;
Alternative
You will get result but this is just a workaround and easy alternative to your problem but not a good one.
select s.name AS 'NAME', min(si.SHOP_IMG_PATH) AS 'PATH', count(*) AS 'AMOUNT',
from
stab t
inner join shop s on (s.shop_id = t.shop_id)
inner join SHOP_IMG si on (s.shop_id= si.SHOP_ID)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name
order by 3 desc,1 asc
This second query will return result as per your need
group by s.name, si.SHOP_IMG_PATH
You're telling it to differentiate them according to SHOP_IMG_PATH. Hence, it shows 4 results, one for each of those.
You'll have to drop SHOP_IMG_PATH from the select clause, if you won't let it use it.
Edit
Got your comment. What you're looking for is random aggregation. This is achieved diferently on different SQL engines. Google around for the one you're using.
If it's Oracle, as indicated by the question tag, here
I solved my problem by using below query,
select s.name,t.shop_id,(select min(SHOP_IMG_PATH) from SHOP_IMG si where shop_id =t.shop_id),count(*) amount from stab t
inner join shop s on (s.shop_id = t.shop_id)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name,t.shop_id
order by 4 desc,1 asc