I have a table like this
CustomerId serviceID from To
id1 serv1 '2016-01-01 07:22:33' '2016-01-05 07:22:33'
id1 serv1 '2016-02-21 08:30:10' '2016-02-27 08:30:10'
id1 serv2 '2016-02-15 18:30:10' '2016-02-15 19:30:10'
id1 serv3 '2016-02-19 18:30:10' '2016-02-19 19:30:10'
id1 serv4 '2017-01-01 08:30:10' '2017-01-01 09:00:10'
where:
serv1 = "in Dog Hospital"
serv2 = "X ray service"
serv3 = "Recovering meal"
For a report, I need to find all those rows that imply the "dog" took that service while in the "Dog hospital" i.e. those services taken during the dates the dog was at the "dog hospital".
Any suggestions, please?
You could check for the rows than fall in serv1's period like this:
select *
from t a
where exists (
select 1
from t b
where serviceId = 'serv1'
and a.`from` >= b.`from`
and a.`to` <= b.`to`
);
Demo # SQLFiddle
Related
Currently I have three tables, namely: hospital, doctor and test. The report generation time is calculated using report time minus the sample test time. How can I write a query to find out which hospital has the least average report generation time?
Table name: hospital
|name|
| 'A' |
| 'B' |
| 'C' |
Table name: doctor
id
doctor_name
hospital_name
1
'Eric'
'A'
2
'Peter'
'A'
3
'Sam'
'B'
4
'Park'
'B'
5
'Alan'
'C'
6
'Andrew'
'C'
Table name: test
id
test_date
test_time
report_date
report_time
doctor_id
1
'2021-10-9'
'19:30:00'
'2021-10-9'
'23:30:00'
1
2
'2021-10-9'
'14:00:00'
'2021-10-9'
'22:20:00'
2
3
'2021-10-9'
'20:30:00'
'2021-10-10'
'08:00:00'
3
4
'2021-10-10'
'07:30:00'
'2021-10-10'
'13:10:00'
4
5
'2021-10-10'
'09:30:00'
'2021-10-10'
'13:30:00'
5
6
'2021-10-10'
'11:00:00'
'2021-10-10'
'22:00:00'
6
7
'2021-10-10'
'15:20:00'
'2021-10-10'
'19:00:00'
1
8
'2021-10-11'
'08:00:00'
'2021-10-11'
'20:00:00'
4
the column hospital_name in table 'doctor' references hospital.name and the column doctor_id in table 'test' references doctor.id
Expected result:
hospital_name
'A'
Explanation: From the 'test' table, we can get the average report generation time of Hospital 'A' is 320 minutes since there are three records about Hospital 'A' (the doctors whose id are 1 and 2) and the average report generation time of Hospital 'B' is 1630 / 3 minutes since there are three records about Hospital 'B' (the doctors whose id are 3 and 4) and the average report generation time of Hospital 'C' is 450 minutes since there are two records about Hospital 'C' (the doctors whose id are 5 and 6). As a result, the answer is Hospital 'A'.
select TIMESTAMPDIFF(minute, timestamp(test_date,test_time),
timestamp(report_date, report_time)) from test as t
inner join doctor as d
on t.doctor_id = d.id
inner join hospital as h
on d.hospital_name = h.name;
I don't know how to find the average generation time
select h.name as hospital_name, count(t.id) as total_tests, SUM(TIMESTAMPDIFF(minute, timestamp(test_date,test_time),
timestamp(report_date, report_time))) as total_time, (SUM(TIMESTAMPDIFF(minute, timestamp(test_date,test_time),
timestamp(report_date, report_time)))/count(t.id)) as avg_time from test as t
inner join doctor as d
on t.doctor_id = d.id
inner join hospital as h
on d.hospital_name = h.name group by h.id
After executing query, you can get these results, check them
I have a legacty table "wages" that I cannot change and I want to get results from this table such that i get allowedWage for a country based on whether there is a value for farmer or not otherwise get the allowedWage for worker
Input
id country farmer worker allowedWage
1 US 1 null 100
2 US null 1 50
3 AU 1 null 60
4 CA null 1 80
Expected Output
id country allowedWage
1 US 100
3 AU 60
4 CA 80
so I wrote the following query if someone wants to find the wage for country US, AU, CA and IN
select id, country, allowedWage from wages
where country in ('US', 'AU', 'CA', 'IN')
and ((farmer = 1 and worker is null) or (worker = 1 or farmer is null))
but this obviously gives all row and I am trying to figure out if there is a way to exclude worker data for a country if there is value of farmer
Actual Output
id country allowedWage
1 US 100
2 US 50
3 AU 60
4 CA 80
You can do it with conditional aggregation:
SELECT country,
COALESCE(MAX(CASE WHEN farmer THEN allowedWage END), MAX(allowedWage)) allowedWage
FROM wages
GROUP BY COUNTRY
For MySql 8.0+ you can do it with FIRST_VALUE() window function:
SELECT DISTINCT country,
FIRST_VALUE(allowedWage) OVER (PARTITION BY country ORDER BY farmer = 1 DESC) allowedWage
FROM wages
See the demo.
Results:
> country | allowedWage
> :------ | ----------:
> AU | 60
> CA | 80
> US | 100
Hmmm . . . this a prioritization query. You can use not exists to select the workers where necessary:
select id, country, allowedWage
from t
where farmer = 1 or
not exists (select 1
from t t2
where t2.country = t.country and t2.farmer = 1
);
Note that the worker column doesn't seem necessary because all the information needed is in the farmer column.
You could use row_number(), if you are running MySQL 8.0.
select *
from (
select t.*,
row_number() over(partition by country order by (farmer <=> 1) desc) rn
from mytable t
)
where rn = 1
How to get those entries which have more than 1 records?
If it doesn't make sense... let me explain:
From the below table I want to access the sum of the commission of all rows where type is joining and "they have more than 1 entry with same downmem_id".
I have this query but it doesn't consider more entries scenario...
$search = "SELECT sum(commission) as income FROM `$database`.`$memcom` where type='joining'";
Here's the table:
id mem_id commission downmem_id type time
2 1 3250 2 joining 2019-09-22 13:24:40
3 45 500 2 egbvegr new time
4 32 20 2 vnsjkdv other time
5 23 2222 2 vfdvfvf some other time
6 43 42 3 joining time
7 32 353 5 joining time
8 54 35 5 vsdvsdd time
Here's the expected result: it should be the sum of the id no 2, 7 only
ie. 3250+353=whatever.
It shouldn't include id no 6 because it has only 1 row with the same downmem_id.
Please help me to make this query.
Another approach is two levels of aggregation:
select sum(t.commission) income
from (select sum(case when type = 'joining' then commission end) as commission
from t
group by downmem_id
having count(*) > 1
) t;
The main advantage to this approach is that this more readily supports more complex conditions on the other members of each group -- such as at most one "joining" record or both "joining" records and no more than two "vnsjkdv" records.
Use EXISTS:
select sum(t.commission) income
from tablename t
where t.type = 'joining'
and exists (
select 1 from tablename
where id <> t.id and downmem_id = t.downmem_id
)
See the demo.
Results:
| income |
| ----- |
| 3603 |
You can use subquery that will find all downmem_id having more than one occurrence in the table.
SELECT Sum(commission) AS income
FROM tablename
WHERE type = 'joining'
AND downmem_id IN (SELECT downmem_id
FROM tablename t
GROUP BY downmem_id
HAVING Count(id) > 1);
DEMO
I have a table with three columns: Name, Country, Price and I need a SQL query that creates a fourth Boolean column named Qualify. This column needs to be true if Price<100 and there is no other row with price<100 and the same country.
Example:
Name - Country- Price- Qualify
Daniel - ES - 98 - TRUE
John - PT - 45 - TRUE
Maria - UK - 102 - FALSE
Anna - PT - 31 - FALSE (because there is already a row with PT and Price<100)
Joseph - UK - 25 - TRUE
Miriam -DK - 105 - FALSE
All this is because I do not want to count volumes more than one time if the price is under 100 and the country is the same. Is this even possible? Thanks
Think exists. In MySQL, you don't even need a case expression:
select t.*,
(t.price < 100 and
not exists (select 1
from t t2
where t2.country = t.country and t2.name <> t.name and t2.price < 100
)
) as flag
from t;
This assumes that name is unique, at least with respect to country.
Just providing another option using CASE statement:
Select
#row_number:=CASE
WHEN #country = Country AND Price < 100 AND #price < 100
THEN 1
ELSE 0 END AS Qualify,
#country:= Country As Country,
#price:= Price As Price
FROM
Test
ORDER BY Country, Price
Here is the demo
Please review my tables below... Is it possible to build a single query capable of
1) calculating the SUM of total_time for all vehicles that have class_id 1 (regardless of feature_id)(result would be 6:35)
2) calculating the SUM of total_time for all vehicles that have class_id 1 AND have feature_id 2(result would be 5:35 based on vehicle_id 22 and 24)
I'm able to get the results in two seperate queries, but I was hoping to retrieve them in one single query.... something like:
SELECT
SUM((CASE WHEN (VEHICLE_TABLE.class_id = 1) then LOG_TABLE.total_time else 0 end)) **AS TOTAL_ALL**,
...here goes statement for 2)... AS TOTAL_DIESEL...
FROM LOG_TABLE, VEHICLE_TABLE .....
WHERE VEHICLE_TABLE.vehicle_id = LOG_TABLE.vehicle_id ......
TABLE 1: LOG_TABLE (vehicle_id is NOT unique)
vehicle_id | total_time
--------------|--------------
22 2:00
22 0:30
23 1:00
24 2:20
24 0:45
TABLE 2: VEHICLE_TABLE (vehicle_id is unique)
vehicle_id | class_id
--------------|--------------
22 1
23 3
24 1
TABLE 3: VEHICLE_FEATURES_TABLE (vehicle_id is NOT unique but feature_id is unique per vehicle_id)
vehicle_id | feature_id
--------------|--------------
22 1
22 2
23 1
23 2
23 6
24 2
24 6
SELECT SUM(lt.total_time) AS TOTAL_ALL,
SUM(CASE WHEN (vft.feature_id IS NOT NULL) then LOG_TABLE.total_time else 0 end) AS FEATURE_TOTAL
FROM VEHICLE_TABLE vt
JOIN LOG_TABLE lt
ON vt.vehicle_id = lt.vehicle_id
LEFT JOIN VEHICLE_FEATURES_TABLE vft
ON vt.vehicle_id = vft.vehicle_id AND vft.feature_id = 2
WHERE vt.class_id = 1
It seems that there is not much point in putting both of them in one query unless you want the results together.
If so, just add a UNION between the 2 queries.
If you want to have both values in the same row try something like this:
SELECT (SELECT Sum(X)
FROM TBL
WHERE CLASS_ID = 1) AS CLS_id1,
(SELECT Sum(X)
FROM TBL
WHERE CLASS_ID = 1
AND FEATURE_ID = 2) AS CLS_id1_FTR_ID2