Sum and distinct dont alter results? - sql

I am a novice trying to work through this here with no luck so far, any help is greatly appreciated!!!
Select Distinct
(AB.agency_no || '-' || ab.branch_no) AS "AGENCY-BRANCH",
count (AB.agency_no || '-' || ab.branch_no) AS Occurences,
A.AGY_NAME AS AGENCY,
Sum(AB.annual_premium) as Premium
From Agency_Book_View AB, Agency A, Branch B
Where AB.agency_no = A.Agency_No
AND B.EXPIRATION_DATE = TO_DATE('12-31-2078', 'MM-DD-YYYY')
AND B.EFFECTIVE_DATE <= sysdate and b.effective_date >=sysdate - 364
Group by AB.agency_no || '-' || ab.branch_no, A.Agy_Name, ab.annual_premium
Order by AB.agency_no || '-' || ab.branch_no
So I am trying to return total annual premium per "agency-branch" and I am getting multiple occurrences of agency-branch. I am trying to get one line per agency branch. I hope this is clear. I tried to include a result set but wasnt allowed to include a picture in my post.
Thanks very much!
Brad

Try this :
SELECT (AB.agency_no || '-' || AB.branch_no) AS "AGENCY-BRANCH",
COUNT(AB.agency_no || '-' || AB.branch_no) AS Occurences,
A.AGY_NAME AS AGENCY,
SUM(AB.annual_premium) AS Premium
FROM Agency_Book_View AB, Agency A, Branch B
WHERE AB.agency_no = A.Agency_No AND AB.branch_no = B.branch_no
AND B.EXPIRATION_DATE = TO_DATE('12-31-2078', 'MM-DD-YYYY')
AND B.EFFECTIVE_DATE <= SYSDATE AND B.effective_date >= SYSDATE - 364
GROUP BY AB.agency_no || '-' || AB.branch_no, A.Agy_Name
ORDER BY AB.agency_no || '-' || AB.branch_no
I joined B table and AB table, removed the DISTINCT and the GROUPed BY ab.annual_premium.

I think you need to remove ab.annual_premium from the group by clause.

Related

selecting values in same time period sqlite

Consider Table Events
Date Time Duration Event
1-1-2023 20:28:00 95 A
1-1-2023 20:29:00 60 B
1-1-2023 20:29:55 10 C
1-1-2023 21:12:00 2 D
...
Now i want to get entries happening in same time period, so for example activity A happens from 20:28:00 to 20:29:35, and activity B happens in time period of 20:29:00 to 20:30:00
So Event A and B have common 35 seconds and B and C has common 5 secs.
i want to get all events in common time period, is it possible using just sql query?
Assuming that your dates are in the proper ISO format YYYY-MM-DD, you can use a self join:
SELECT *
FROM events e1 INNER JOIN events e2
ON e2.event > e1.event
AND datetime(e2.date || ' ' || e2.time, e2.duration || ' second') > e1.date || ' ' || e1.time
AND e2.date || ' ' || e2.time < datetime(e1.date || ' ' || e1.time, e1.duration || ' second');
See the demo.
Maybe, supposing you have index on date-time
SELECT *
FROM events e1 INNER JOIN events e2
ON datetime(e2.date || ' ' || e2.time)
BETWEEN (e1.date || ' ' || e1.time)
AND datetime(e1.date || ' ' || e1.time, e1.duration || ' second')
WHERE e2.event <> e1.event;
As #forpas says, if you kept date an time values in a single column, and have index on this column, performance will be better

How to use MAX() for multiple dates in SQLite?

My goal is to choose the PTID with the most recent date with its recent time. I was trying to use the MAX() function to choose the most recent date with its recent time but received an error syntax (see the double asterisk on Line 9 in my code). Is there a statement to do that or would it be easier to do it in Python? I appreciate all the help!
Table 1
PTID
RESULT_DATE1
RESULT_TIME
DIAGNOSIS_CD
54
2020-01-06
10:03:02
W34
54
2020-01-01
09:18:05
S38
54
2020-01-01
03:08:45
V98
54
2020-04-04
02:09:08
V98
54
2020-04-04
12:12:34
V89
My Goal:
PTID
RESULT_DATE1
RESULT_TIME
DIAGNOSIS_CD
54
2020-04-04
12:12:34
V98
54
2020-01-06
10:03:02
W34
54
2020-01-01
09:18:05
S38
My Code:
CREATE TABLE covid AS
SELECT t1.*, t2.*
FROM lab9 t1 JOIN diagnosis9 t2 ON t2.PTID = t1.PTID
AND t1.RESULT_DATE1 || ' ' || t1.RESULT_TIME
BETWEEN
date(t2.diagdate1, '-7 day') || ' ' || t2.DIAG_TIME
AND
t2.diagdate1 || ' ' || t2.DIAG_TIME
**WHERE RESULT_DATE1 = MAX(RESULT_DATE1)**
GROUP BY t1.PTID || DIAGNOSIS_CD
ORDER BY t1.PTID;
First, you should not group by the concatenation of 2 columns because this may lead to unexpected results.
You should group by the 2 columns.
Also, you can't use an aggregate function like MAX() in the WHERE clause of a query.
What you need is the max value of the expression t1.RESULT_DATE1 || ' ' || t1.RESULT_TIME which you can finally split to date and time with the functions date() and time():
CREATE TABLE covid AS
SELECT t1.PTID,
date(MAX(t1.RESULT_DATE1 || ' ' || t1.RESULT_TIME)) RESULT_DATE1,
time(MAX(t1.RESULT_DATE1 || ' ' || t1.RESULT_TIME)) RESULT_TIME,
t2.*
FROM lab9 t1 JOIN diagnosis9 t2
ON t2.PTID = t1.PTID
AND t1.RESULT_DATE1 || ' ' || t1.RESULT_TIME
BETWEEN
date(t2.diagdate1, '-7 day') || ' ' || t2.DIAG_TIME AND t2.diagdate1 || ' ' || t2.DIAG_TIME
GROUP BY t1.PTID, t2.DIAGNOSIS_CD
ORDER BY t1.PTID;
The above query will return the rows with the max datetime for each combination of PTID and DIAGNOSIS_CD with the use if SQLite's feature of bare columns.

SQL Select Query for 365 Days

I am trying to create an SQL query to select percentage utilization for my team members.
I am looking for a to daily basis select query to show the utilization when it is greater than 0 and to show '0' when it is null. In order to be able to plot those figures later on as a line chart.
I have written 365 of the following select query and I have combined them together using "UNION ALL" method. It is working now, but it is extremely slow!.
If you have a better idea to produce the daily outputs for the 365 days, that will be great.
Many thanks in advance.
Kind regards
Mohamed
Code:
.........................
SELECT ifnull((
SELECT SUM(CAST(pc_loading.value AS INT))
FROM ticket
JOIN ticket_custom start_date ON (ticket.id = start_date.ticket AND start_date.name = 'planned_start_date')
JOIN ticket_custom finish_date ON (ticket.id = finish_date.ticket AND finish_date.name = 'planned_finish_date')
JOIN ticket_custom pc_loading ON (ticket.id = pc_loading.ticket AND pc_loading.name = 'percentage_loading')
WHERE UPPER(ticket.owner)='#########'
AND ticket.type = 'Internal Resource'
AND DATE(substr(start_date.value, 7, 4) || '-' || substr(start_date.value, 4, 2) || '-' || substr(start_date.value, 1, 2)) <= DATE('2020-01-01')
AND DATE(substr(finish_date.value, 7, 4) || '-' || substr(finish_date.value, 4, 2) || '-' || substr(finish_date.value, 1, 2)) >= DATE('2020-01-01')
AND status NOT IN ("closed", "suspended")) , 0) UNION ALL
SELECT ifnull((
SELECT SUM(CAST(pc_loading.value AS INT))
FROM ticket
JOIN ticket_custom start_date ON (ticket.id = start_date.ticket AND start_date.name = 'planned_start_date')
JOIN ticket_custom finish_date ON (ticket.id = finish_date.ticket AND finish_date.name = 'planned_finish_date')
JOIN ticket_custom pc_loading ON (ticket.id = pc_loading.ticket AND pc_loading.name = 'percentage_loading')
WHERE UPPER(ticket.owner)='#########'
AND ticket.type = 'Internal Resource'
AND DATE(substr(start_date.value, 7, 4) || '-' || substr(start_date.value, 4, 2) || '-' || substr(start_date.value, 1, 2)) <= DATE('2020-01-02')
AND DATE(substr(finish_date.value, 7, 4) || '-' || substr(finish_date.value, 4, 2) || '-' || substr(finish_date.value, 1, 2)) >= DATE('2020-01-02')
AND status NOT IN ("closed", "suspended")) , 0) UNION ALL
.......etc
....................................
Use a recursive CTE which returns all the dates of 2020, cross join it to your query and group by each date:
with recursive days as (
select date('2020-01-01') date
union all
select date(date, '+1 day')
from days
where strftime('%Y', date, '+1 day') = '2020'
)
SELECT days.date, COALESCE(SUM(CAST(pc_loading.value AS INT)), 0)
FROM days
CROSS JOIN ticket
JOIN ticket_custom start_date ON (ticket.id = start_date.ticket AND start_date.name = 'planned_start_date')
JOIN ticket_custom finish_date ON (ticket.id = finish_date.ticket AND finish_date.name = 'planned_finish_date')
JOIN ticket_custom pc_loading ON (ticket.id = pc_loading.ticket AND pc_loading.name = 'percentage_loading')
WHERE UPPER(ticket.owner)='#########' AND ticket.type = 'Internal Resource'
AND DATE(substr(start_date.value, 7, 4) || '-' || substr(start_date.value, 4, 2) || '-' || substr(start_date.value, 1, 2)) <= days.date
AND DATE(substr(finish_date.value, 7, 4) || '-' || substr(finish_date.value, 4, 2) || '-' || substr(finish_date.value, 1, 2)) >= days.date
AND status NOT IN ("closed", "suspended")
GROUP BY days.date
Also, you would find significant improvement in performance if you stored the dates in a comparable format like YYYY-MM-DD since there would be no need for all these rearrangements/concatenations in the WHERE clause.
Alternative without the use of the CTE:
SELECT days.date, COALESCE(SUM(CAST(pc_loading.value AS INT)), 0)
FROM (
SELECT '2020-01-01' date UNION ALL SELECT '2020-01-02' UNION ALL
SELECT '2020-01-03' UNION ALL SELECT '2020-01-04' UNION ALL
............................................................
) days
CROSS JOIN ticket
JOIN ticket_custom start_date ON (ticket.id = start_date.ticket AND start_date.name = 'planned_start_date')
JOIN ticket_custom finish_date ON (ticket.id = finish_date.ticket AND finish_date.name = 'planned_finish_date')
JOIN ticket_custom pc_loading ON (ticket.id = pc_loading.ticket AND pc_loading.name = 'percentage_loading')
WHERE UPPER(ticket.owner)='#########' AND ticket.type = 'Internal Resource'
AND DATE(substr(start_date.value, 7, 4) || '-' || substr(start_date.value, 4, 2) || '-' || substr(start_date.value, 1, 2)) <= days.date
AND DATE(substr(finish_date.value, 7, 4) || '-' || substr(finish_date.value, 4, 2) || '-' || substr(finish_date.value, 1, 2)) >= days.date
AND status NOT IN ("closed", "suspended")
GROUP BY days.date

Don't show query results if they appear in the other query

In my application each manager has a work pattern (for example Monday-Friday). But I also have a table "pattern_changes" where they can insert data if they cannot be present at work.
With the first query I can show who is available today, according to the pattern assigned to them:
SELECT distinct gu.first_name || ' ' || gu.last_name
FROM patterns pa JOIN fmanager_pattern fp
ON pa.id = fp.pattern_id
JOIN fmanagers fm
ON fm.id = fp.fmanager_id
JOIN gen_users gu
ON gu.user_id = fm.user_id
WHERE (TO_CHAR(pa.start_dt, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') LIKE TO_CHAR(sysdate, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') AND pa.start_dt < sysdate and pa.end_dt > sysdate)
OR (TO_CHAR(pa.end_dt, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') LIKE TO_CHAR(sysdate, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') AND pa.start_dt < sysdate and pa.end_dt > sysdate)
OR TO_CHAR(sysdate, 'D') BETWEEN TO_CHAR(pa.start_dt, 'D') AND TO_CHAR(pa.end_dt, 'D') AND pa.start_dt < sysdate and pa.end_dt > sysdate
OR TO_CHAR(sysdate, 'D')+7 BETWEEN TO_CHAR(pa.start_dt, 'D') AND TO_CHAR(pa.start_dt, 'D')+7 AND pa.start_dt < sysdate and pa.end_dt > sysdate
In the second query I can show who is not available today, according to the pattern_changes table.
SELECT fm.id, gu.first_name || ' ' || gu.last_name
FROM fmanagers fm JOIN pattern_changes pc
ON pc.fmanagers_id = fm.id
JOIN gen_users gu
ON gu.user_id = fm.user_id
WHERE pc.change_dt < sysdate and pc.end_dt > sysdate
OR pc.change_dt = to_char(sysdate)
OR pc.end_dt = to_char(sysdate))
For example, the first query returns: ADAM and EVA
The second query returns ADAM
So I just want to see EVA as a result.
I tried to do it with NOT IN or NOT EXISTS but neither of them work.
Can anybody help?
Thank you in advance

Query Items which were resold within 1 year of last selling date

I have a table with details of sold cars. Some of these cars have been resold within last 1, 2 or 3 years. The table looks like this:
Car_Type || Car_Reg_No || Sold_Date || Listing_No
Hatch || 23789 || 2017-02-03 11:26 || X6529
Coupe || 16723 || 2016-11-07 09:40 || N8156
Sedan || 35216 || 2016-05-23 10:34 || M8164
Hatch || 23789 || 2016-09-16 04:30 || O7361
Now, I need to query records (cars) which were re-sold within 1 year of their latest sold date and how many times were they sold. So, my output would be like this:
Car_Type || Car_Reg_No || Sold_Count || Latest_Sold_Date
Hatch || 23789 || 2 || 2017-02-03 11:26
In essence, How do I check for re-sold records within a specific time frame of their latest sold date?
You can do this by finding the max, and joining based on your conditions.
declare #TableA table (Car_Type varchar(64)
,Car_Reg_No int
,Sold_Date datetime
,Listing_No varchar(6))
insert into #TableA
values
insert into #TableA
values
('Hatch',23789,'2017-02-03 11:26','X6529'),
('Coupe',16723,'2017-11-07 09:40','N8156'),
('Sedan',35216,'2017-05-23 10:34','M8164'),
('Hatch',23789,'2016-09-16 04:30','O7361'),
('Coupe',16723,'2014-11-07 09:40','N8156')
;with cte as(
select
Car_Type
,Car_Reg_No
,Latest_Sold_Date = max(Sold_Date)
from
#TableA
group by
Car_Type
,Car_Reg_No)
select
a.Car_Type
,a.Car_Reg_No
,Sold_Count = count(b.Listing_No) + 1
,a.Latest_Sold_Date
from cte a
inner join
#TableA b on
b.Car_Reg_No = a.Car_Reg_No
and b.Sold_Date != a.Latest_Sold_Date
and datediff(day,b.Sold_Date,a.Latest_Sold_Date) < 366
--if you want only cars which were sold within last year too, uncomment this
--and datediff(day,a.Latest_Sold_Date,getdate()) < 366
group by
a.Car_Type
,a.Car_Reg_No
,a.Latest_Sold_Date
By my understanding..,
select sd1.Car_Type, sd1.Car_Reg_No,
count(sd1.Car_Reg_No) + 1 'no of sales in last one year', --1 is added because, see the last condition
sd1.Sold_Date 'Last sold date'
from(
select *,ROW_NUMBER() over(partition by Car_Reg_No order by sold_date desc) as rn from #Table) as sd1
join
(select * from #Table) as sd2
on sd1.Car_Type = sd2.Car_Type
and DATEDIFF(dd,sd2.Sold_Date,sd1.Sold_Date) < 366
and sd1.rn = 1
and sd1.Sold_Date <> sd2.Sold_Date -- here last sold is eliminated. so count is added by one.
group by sd1.Car_Type,sd1.Sold_Date, sd1.Car_Reg_No
order by sd1.Car_Reg_No