sql select from table with date range condition - mysql

I have this table
CREATE TABLE `tarif` (
`tarif_id` int(11) NOT NULL AUTO_INCREMENT,
`start_tarif` date NOT NULL,
`end_tarif` date NOT NULL,
`day_tarif` varchar(50) NOT NULL,
PRIMARY KEY (`tarif_id`)
);
INSERT INTO `tarif` VALUES (1, '2019-02-01', '2019-02-10', '10'),
(2, '2019-02-11', '2019-02-20', '20'),
(3, '2019-02-21', '2019-02-28', '10'),
(4, '2019-03-01', '2019-02-10', '15');
How can I get day_tarif between 2019-02-05 and 2019-02-15 and calculate the sum = day_tarif * number of date betwwen 2019-02-05 and 2019-02-15

You can use the following solution using DATEDIFF:
SELECT SUM((DATEDIFF(LEAST(`end_tarif`, '2019-02-15'), GREATEST(`start_tarif`, '2019-02-05')) + 1) * `day_tarif`) AS sumCustom
FROM `tarif`
WHERE `end_tarif` >= '2019-02-05' AND `start_tarif` <= '2019-02-15'
demo on dbfiddle.uk
You can use the following solution using SUM and COUNT:
SELECT SUM(`day_tarif`) * COUNT(`tarif_id`)
FROM `tarif`
WHERE `end_tarif` >= '2019-02-05' AND `start_tarif` <= '2019-02-15'

select SUM(day_tarif) * COUNT(tarif_id)
from tarif
where end_date >= '2019-02-05' AND start_date <= '2019-02-15'
This question has been asked several times, or something like it. Be sure to search StackOverflow before asking a duplicate: SQL query to select dates between two dates

You can try following code:
WITH cte AS(
SELECT *
FROM tablename
WHERE end_tarif >= '2019-02-05' AND start_tarif <= '2019-02-15'
)
SELECT day_tarif, day_tarif * COUNT(tarif_id) AS 'SUM'
FROM cte
group by day_tarif;

I think this might be what you are after...
Declare #tarif as table (
tarif_id int NOT NULL ,
start_tarif date NOT NULL,
end_tarif date NOT NULL,
day_tarif varchar(50) NOT NULL
);
INSERT INTO #tarif VALUES (1, '2019-02-01', '2019-02-10', '10'),
(2, '2019-02-11', '2019-02-20', '20'),
(3, '2019-02-21', '2019-02-28', '10'),
(4, '2019-03-01', '2019-02-10', '15');
-- Declare parameters
Declare #paramstart date, #paramend date
Set #paramstart='2019-02-05'
Set #paramend='2019-02-15'
-- Set up loop
Declare #mincount int, #maxcount int, #myval int, #curstart date, #curend date,#curtarif int, #mytarif int
Set #mincount=(Select MIN(tarif_id) from #tarif where end_tarif >= '2019-02-05' AND start_tarif <= '2019-02-15')
Set #maxcount=(Select Max(tarif_id) from #tarif where end_tarif >= '2019-02-05' AND start_tarif <= '2019-02-15')
Set #mytarif=0
-- Do loop
WHile #mincount<=#maxcount
BEGIN
Set #curstart=(Select start_tarif from #tarif where tarif_id=#mincount)
Set #curend=(Select end_tarif from #tarif where tarif_id=#mincount)
Set #curtarif=(Select cast(day_tarif as int) from #tarif where tarif_id=#mincount)
IF #paramstart between #curstart and #curend
BEGIN
Set #mytarif=#mytarif+((DATEDIFF(day,#paramstart,#curend)+1) * #curtarif)
END
IF #paramend between #curstart and #curend
BEGIN
Set #mytarif=#mytarif+((DATEDIFF(day,#curstart,#paramend)+1) * #curtarif)
END
IF #paramstart not between #curstart and #curend and #paramend not between #curstart and #curend
BEGIN
Set #mytarif=#mytarif+((DATEDIFF(day,#curstart,#curend)+1) * #curtarif)
END
Set #mincount=#mincount+1
END
Select #mytarif as tarif

Try this!
select day_tarif , sum(day_tarif * count (*)) as sum
where start_tarif between '2019/02/05' and '2019/02/15' and end_tarif between '2019/02/05' and '2019/02/15'
group by day_tarif;

Related

How To Write A Query With A CTE And A Left Join

I am trying to have a calendar table with my CTE and set it up so that my dates in my query display like this
Jan 18Jan 19Feb 18Feb 19
Now this is my DDL and this is the query I attempted, but in MySql Workbench I'm getting the error that there is an error in my sql somewhere.
This is the exact error:
Query Error: Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RECURSIVE cte_months_to_pull AS ( SELECT DATE_FORMAT(#start_date, '%Y-%m-01'' at line 1
Can someone assist?
If it's easier this is a SQL Fiddle of everything http://sqlfiddle.com/#!9/300f9d/1
CREATE TABLE PrevYear (
`EmployeeNumber` char(8) NOT NULL,
`SaleAmount` int DEFAULT NULL,
`SaleDate` date NOT NULL,
`EmployeeName` char(17) NOT NULL
);
CREATE TABLE CurrentYear (
`EmployeeNumber` char(8) NOT NULL,
`SaleAmount` int DEFAULT NULL,
`SaleDate` date NOT NULL,
`EmployeeName` char(17) NOT NULL
);
INSERT INTO CurrentYear
VALUES ('ea12', '100', '2019-01-10', 'Maggie Samuels');
INSERT INTO CurrentYear
VALUES ('ea12', '199', '2019-01-13', 'Sam Stoner');
INSERT INTO CurrentYear
VALUES ('ea12', '100', '2019-03-01', 'Jake Jolel');
INSERT INTO CurrentYear
VALUES ('ls22', '100', '2019-05-01', 'Maggie Samuels');
INSERT INTO PrevYear
VALUES ('ea12', '100', '2018-01-10', 'Maggie Samuels');
INSERT INTO PrevYear
VALUES ('ea12', '199', '2018-01-13', 'Sam Stoner');
INSERT INTO PrevYear
VALUES ('ea12', '100', '2018-03-01', 'Sam Stoner');
INSERT INTO PrevYear
VALUES ('ls22', '100', '2018-05-01', 'Maggie Samuels');
And this is the query I try:
SET #start_date = '20190102';
SET #number_of_months = 12;
WITH RECURSIVE
cte_months_to_pull AS (
SELECT DATE_FORMAT(#start_date, '%Y-%m-01')
- INTERVAL #number_of_months MONTH AS month_to_pull
UNION ALL
SELECT month_to_pull + INTERVAL 1 MONTH
FROM cte_months_to_pull
WHERE month_to_pull < #start_date + INTERVAL #number_of_months - 2 MONTH
)
SELECT Date_format(saledate, '%m-%Y') AS Month,
employeename,
Sum(saleamount) AS IA
FROM currentyear
WHERE employeename = 'Maggie Samuels'
GROUP BY Date_format(saledate, '%m-%Y'), employeename
UNION ALL
SELECT Date_format(saledate, '%m-%Y') AS Month,
employeename,
Sum(saleamount) AS IA
FROM prevyear
WHERE employeename = 'Maggie Samuels'
GROUP BY Date_format(saledate, '%m-%Y'), employeename
LEFT JOIN cte_months_to_pull (
Select DATE_Format(month_to_pull, '%b %y')
FROM cte_months_to_pull
) AS YRS ON month_to_pull = saledate
ORDER BY MONTH(month_to_pull), YEAR(month_to_pull)
As I can see you are using MySQL version older than 8.0 which doesn't support RECURSIVE CTEs. I have tried your query with some minor updates on 8.0 and it worked fine -
WITH RECURSIVE
cte_months_to_pull AS (
SELECT DATE_FORMAT(#start_date, '%Y-%m-01')
- INTERVAL #number_of_months MONTH AS month_to_pull
UNION ALL
SELECT month_to_pull + INTERVAL 1 MONTH
FROM cte_months_to_pull
WHERE month_to_pull < #start_date + INTERVAL #number_of_months - 2 MONTH
)
SELECT YRS.months_to_pull
,T.employeename
,COALESCE(T.IA, 0) IA
FROM (SELECT DATE_Format(month_to_pull, '%b-%Y') months_to_pull
FROM cte_months_to_pull
ORDER BY months_to_pull
) AS YRS
LEFT JOIN (SELECT Date_format(saledate, '%b-%Y') AS `Month`
,employeename
,Sum(saleamount) AS IA
FROM CurrentYear
WHERE employeename = 'Maggie Samuels'
GROUP BY Date_format(saledate, '%b-%Y'), employeename
UNION ALL
SELECT Date_format(saledate, '%b-%Y')
,employeename
,Sum(saleamount)
FROM PrevYear
WHERE employeename = 'Maggie Samuels'
GROUP BY Date_format(saledate, '%b-%Y'), employeename) T
ON YRS.months_to_pull = T.`Month`
ORDER BY month(STR_TO_DATE(CONCAT('01-',months_to_pull), '%d-%b-%Y'))
,YEAR(STR_TO_DATE(CONCAT('01-',months_to_pull), '%d-%b-%Y'))
Here is the Fiddle
Since there is no expected output, I have only tried till running the query.

Query to display row after 1 pm

How to fetch all rows from table where time is greater than 13:00 i.e. 1PM
SELECT * FROM `mytable` WHERE `time` >="13:00";
if you have a datetime field you could do this (I'm assuming here as you haven't specified):
create table tester(`id` int(6), `name` varchar(50), `datetest` datetime);
insert into tester(`id`,`name`,`datetest`)
values(1, 'n1', '2018-12-20 09:00:00'),
(2, 'n2', '2018-12-20 10:00:00'),
(3, 'n3', '2018-12-20 13:10:00'),
(4, 'n4', '2018-12-20 14:00:00');
select * from tester
where TIME(datetest) > '13:00'

Creating a weighted sum of values from different tables

I'm trying to create a list of students whose behaviour is statistically worst across each of our school's year groups.
We have a table named students.
We then have behavioural flags and alerts, plus sanctions.
However, different categories of flag/alert/sanction are deemed more serious than others. These are stored with labels in their respective _categories table, e.g. flag_categories and sanction_categories. The flag table will then have a column called Category_ID (alerts is a bit different as it's just a Type field with 'A', 'C', 'P' and 'S' values).
If I want to look at data which shows our highest-flagged students in a specific year group, I'd run this query:
SELECT
CONCAT(stu.Firstname, " ", stu.Surname) AS `Student`,
COUNT(f.ID) AS `Flags`
FROM `students` stu
LEFT JOIN `flags` f ON f.Student_ID = stu.id
WHERE stu.Year_Group = 9
GROUP BY stu.id
ORDER BY `Flags` DESC
LIMIT 0, 20
If I wanted to show our students with the most Crisis alerts in a specific year group, I'd run this query:
SELECT
CONCAT(stu.Firstname, " ", stu.Surname) AS `Student`,
COUNT(f.ID) AS `Flags`
FROM `students` stu
LEFT JOIN `flags` f ON f.Student_ID = stu.id
WHERE stu.Year_Group = 9
AND f.Category_ID = 10
GROUP BY stu.id
ORDER BY `Flags` DESC
LIMIT 0, 20
If I want to find how many Late or Mobile flags a student has, and perhaps add these together (with weightings), I can run the following query:
SELECT
CONCAT(stu.Firstname, " ", stu.Surname) AS `Student`,
SUM(CASE WHEN f.Category_ID = 10 THEN 1 ELSE 0 END) AS `Late Flags`,
SUM(CASE WHEN f.Category_ID = 12 THEN 2 ELSE 0 END) AS `Mobile Flags`,
## not sure about this line below... is there a nicer way of doing it? `Late Flags` isn't recognised as a field apparently
## so I can't just do ( `Late Flags` + `Mobile Flags` )
(SUM(CASE WHEN f.Category_ID = 10 THEN 1 ELSE 0 END) + SUM(CASE WHEN f.Category_ID = 12 THEN 2 ELSE 0 END)) AS `Points`
FROM `flags` f
LEFT JOIN `students` stu ON f.Student_ID = stu.id
WHERE stu.Year_Group = 9
GROUP BY stu.id
ORDER BY `Points` DESC
LIMIT 0, 20
What I don't understand is how I would do this across myriad tables. I need to be able to weight:
Late (flags, Category_ID = 10), Absconded (flags, Category_ID = 15) and Community flags (flags, Category_ID = 13) plus Safeguarding alerts (alerts, Type = 'S') are all worth 1 point
Behavioural flags (flags, Category_ID IN (1, 7, 8)) are worth 2 points
Process alerts (alerts, Type = 'P') and detention sanctions (sanctions, Category_ID = 1) are worth 3 points
So on and so forth. That's far from an exhaustive list but I've included enough variables to help me get my head round a multi-table weighted sum.
The outcome I'm looking for is just 2 columns - student's name and weighted points.
So, according to the bullet points above, if a student has received 2 Late flags (1 point each) and 1 Process alert (3 points), the output should just say Joe Bloggs and 5.
Can anyone help me to understand how I can get these weighted values from different tables into one SUM'd output for each student?
[edit] SQLFiddle here: http://sqlfiddle.com/#!9/449218/1/0
Note, I am not doing this for the bounty. Please give to someone else.
This could be done with a few LEFT JOINs of derived tables. Note you did not supply the sanctions table. But the below would appear to be well illustrative. So I created a temp table. It would seem to allow for maximum flexibility without overcomplicating a larger left join notion that might be hard to debug. Afterall, you said your real querying will be much more complicated than this. As such, build out the temp table structure more.
This loads a tmp table up with default 0's for the students in the "passed by parameter Student Year" to a stored procedure. Two updates are performed. Then selects for a result set.
Schema / Load:
create schema s38741386; -- create a test database
use s38741386;
CREATE TABLE `students` (
`id` int(11) PRIMARY KEY,
`Firstname` varchar(50) NOT NULL,
`Surname` varchar(50) NOT NULL,
`Year_Group` int(2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
# STUDENT INSERTS
INSERT INTO `students`
(`id`, `Firstname`, `Surname`, `Year_Group`)
VALUES
(201, 'Student', 'A', 9),
(202, 'Student', 'B', 9),
(203, 'Student', 'C', 9),
(204, 'Student', 'D', 9),
(205, 'Student', 'E', 9);
CREATE TABLE `alert` (
`ID` int(11) PRIMARY KEY,
`Staff_ID` int(6) NOT NULL,
`Datetime_Raised` datetime NOT NULL,
`Room_Label` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
`Type` enum('A','C','P','Q','S') COLLATE utf8_unicode_ci NOT NULL COMMENT 'A=Absconded, C=Crisis, P=Process, Q=Quiet, S=Safeguarding',
`Details` text COLLATE utf8_unicode_ci,
`Responder` int(8) DEFAULT NULL,
`Datetime_Responded` datetime DEFAULT NULL,
`Room_ID` int(11) NOT NULL COMMENT 'will be linked to internal room id.',
`Status` varchar(1) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'O:ngoing, R:esolved'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# ALERT INSERTS
INSERT INTO `alert`
(`ID`, `Staff_ID`, `Datetime_Raised`, `Room_Label`, `Type`, `Details`, `Responder`, `Datetime_Responded`, `Room_ID`, `Status`)
VALUES
(1, '101', '2016-08-04 00:00:00', NULL, 'P', NULL, '103', '2016-08-04 00:00:01', '15', 'R'),
(2, '102', '2016-08-04 00:00:00', NULL, 'P', NULL, '103', '2016-08-04 00:00:01', '15', 'R'),
(3, '102', '2016-08-04 00:00:00', NULL, 'P', NULL, '103', '2016-08-04 00:00:01', '15', 'R'),
(4, '101', '2016-08-04 00:00:00', NULL, 'P', NULL, '103', '2016-08-04 00:00:01', '15', 'R');
CREATE TABLE `alert_students` (
`ID` int(11) PRIMARY KEY,
`Alert_ID` int(6) NOT NULL,
`Student_ID` int(6) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# ALERT_STUDENT INSERTS
INSERT INTO `alert_students`
(`ID`, `Alert_ID`, `Student_ID`)
VALUES
(1, '1', '201'),
(2, '1', '202'),
(3, '2', '201'),
(4, '3', '202'),
(5, '4', '203'),
(6, '5', '204');
CREATE TABLE `flags` (
`ID` int(11) PRIMARY KEY,
`Staff_ID` int(11) NOT NULL,
`Student_ID` int(11) NOT NULL,
`Datetime` datetime NOT NULL,
`Category_ID` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
# ALERT INSERTS
-- TRUNCATE TABLE flags;
INSERT INTO `flags`
(`ID`, `Staff_ID`, `Student_ID`, `Datetime`, `Category_ID`)
VALUES
(1, '101', '201', '2016-08-04 00:00:01', 10),
(2, '102', '202', '2016-08-04 00:00:02', 12),
(3, '102', '203', '2016-08-04 00:00:03', 10),
(4, '101', '204', '2016-08-04 00:00:04', 13),
(5, '102', '202', '2016-08-04 00:00:02', 12),
(6, '102', '203', '2016-08-04 00:00:03', 10),
(7, '101', '204', '2016-08-04 00:00:04', 13),
(8, '102', '202', '2016-08-04 00:00:02', 10),
(9, '102', '203', '2016-08-04 00:00:03', 10),
(10, '101', '204', '2016-08-04 00:00:04', 7),
(11, '101', '204', '2016-08-04 00:00:07', 8),
(12, '101', '204', '2016-08-04 00:00:08', 1),
(13, '101', '204', '2016-08-04 00:00:09', 8);
Stored Procedure:
DROP PROCEDURE IF EXISTS rptSM_by_year;
DELIMITER $$
CREATE PROCEDURE rptSM_by_year
( pSY INT -- parameter student year
)
BEGIN
DROP TEMPORARY TABLE IF EXISTS tmpStudentMetrics;
CREATE TEMPORARY TABLE tmpStudentMetrics
( `StudentId` int(11) PRIMARY KEY,
LateFP INT NOT NULL,
MobiFP INT NOT NULL,
AbscFP INT NOT NULL,
CommFP INT NOT NULL,
SafeAP INT NOT NULL,
BehaFP INT NOT NULL,
ProcAP INT NOT NULL
)ENGINE=InnoDB;
INSERT tmpStudentMetrics (StudentId,LateFP,MobiFP,AbscFP,CommFP,SafeAP,BehaFP,ProcAP)
SELECT id,0,0,0,0,0,0,0
FROM students
WHERE Year_Group = pSY;
UPDATE tmpStudentMetrics tmp
JOIN
( SELECT
stu.id,
SUM(CASE WHEN f.Category_ID = 10 THEN 1 ELSE 0 END) AS `LateFP`,
SUM(CASE WHEN f.Category_ID = 15 THEN 1 ELSE 0 END) AS `AbscFP`,
SUM(CASE WHEN f.Category_ID = 13 THEN 1 ELSE 0 END) AS `CommFP`,
SUM(CASE WHEN f.Category_ID = 12 THEN 2 ELSE 0 END) AS `MobiFP`,
SUM(CASE WHEN f.Category_ID IN (1,7,8) THEN 2 ELSE 0 END) AS `BehaFP`
FROM `flags` f
LEFT JOIN `students` stu ON f.Student_ID = stu.id
WHERE stu.Year_Group = pSY
GROUP BY stu.id
) xDerived
ON xDerived.id=tmp.StudentId
SET tmp.LateFP=xDerived.LateFP,
tmp.AbscFP=xDerived.AbscFP,
tmp.CommFP=xDerived.CommFP,
tmp.MobiFP=xDerived.MobiFP,
tmp.BehaFP=xDerived.BehaFP;
UPDATE tmpStudentMetrics tmp
JOIN
( SELECT
stu.id,
SUM(CASE WHEN a.Type = 'S' THEN 1 ELSE 0 END) AS `SafeAP`,
SUM(CASE WHEN a.Type = 'P' THEN 3 ELSE 0 END) AS `ProcAP`
FROM `alert_students` als
JOIN `alert` a
ON a.ID=als.Alert_ID
JOIN `students` stu
ON stu.id=als.Student_ID and stu.Year_Group = pSY
GROUP BY stu.id
) xDerived
ON xDerived.id=tmp.StudentId
SET tmp.SafeAP=xDerived.SafeAP,
tmp.ProcAP=xDerived.ProcAP;
-- SELECT * FROM tmpStudentMetrics; -- check detail
SELECT stu.id,
CONCAT(stu.Firstname, " ", stu.Surname) AS `Student`,
tmp.LateFP+tmp.MobiFP+tmp.AbscFP+tmp.CommFP+tmp.SafeAP+tmp.BehaFP+tmp.ProcAP AS `Points`
FROM `students` stu
JOIN tmpStudentMetrics tmp
ON tmp.StudentId=stu.id
WHERE stu.`Year_Group` = pSY
ORDER BY stu.id;
-- SELECT * FROM tmpStudentMetrics; -- check detail
DROP TEMPORARY TABLE IF EXISTS tmpStudentMetrics;
-- TEMP TABLES are connection based. Explicityly dropped above for safety when done.
-- Depends on your connection type and life-span otherwise.
END$$
DELIMITER ;
Test:
call rptSM_by_year(9);
+-----+-----------+--------+
| id | Student | Points |
+-----+-----------+--------+
| 201 | Student A | 7 |
| 202 | Student B | 11 |
| 203 | Student C | 6 |
| 204 | Student D | 10 |
| 205 | Student E | 0 |
+-----+-----------+--------+
Cleanup:
drop schema s38741386; -- drop the test database
Think all you have asked can be done with a subquery and a couple of sub-SELECTs:
SELECT `Student`,
`Late Flags` * 1
+ `Absconded Flags` * 1
+ `Community Flags` * 1
+ `Safeguarding Alerts Flags` * 1
+ `Behavioural flags` * 2
+ `Process Alerts Flags` * 3 AS `Total Points`
FROM
(
SELECT
CONCAT(stu.Firstname, " ", stu.Surname) AS `Student`,
SUM(CASE WHEN f.Category_ID = 10 THEN 1 ELSE 0 END) AS `Late Flags`,
SUM(CASE WHEN f.Category_ID = 12 THEN 1 ELSE 0 END) AS `Mobile Flags`,
SUM(CASE WHEN f.Category_ID = 15 THEN 1 ELSE 0 END) AS `Absconded Flags`,
SUM(CASE WHEN f.Category_ID = 13 THEN 1 ELSE 0 END) AS `Community Flags`,
(SELECT COUNT(*) FROM `alert` a JOIN `alert_students` ast ON ast.`Alert_ID` = a.`ID`
WHERE ast.`Student_ID` = stu.`id` AND a.`Type` = 'S') AS `Safeguarding Alerts Flags`,
SUM(CASE WHEN f.Category_ID IN (1, 7, 8) THEN 1 ELSE 0 END) AS `Behavioural flags`,
(SELECT COUNT(*) FROM `alert` a JOIN `alert_students` ast ON ast.`Alert_ID` = a.`ID`
WHERE ast.`Student_ID` = stu.`id` AND a.`Type` = 'P') AS `Process Alerts Flags`
FROM `students` stu
LEFT JOIN `flags` f ON f.Student_ID = stu.id
WHERE stu.Year_Group = 9
GROUP BY stu.id
LIMIT 0, 20
) subq
ORDER BY `Total Points` DESC;
The above query includes everything you mentioned apart from sanctions (as your original SQL Fiddle demo didn't include this table).
Demo
An updated fiddle with the above query is here: http://sqlfiddle.com/#!9/449218/39.
You could use union all
Basically you create all your individual queries for each table and connect them all together using union all.
Here is an example, I used your student table twice but you would change the second one to what ever other table you want. SQLFiddle
You can do it with LEFT JOINS:
SELECT CONCAT(stu.firstname,' ', stu.surname) student,
COALESCE(f_group.weight_sum,0) + COALESCE(a_group.weight_sum,0) + COALESCE(s_group.weight_sum,0) points
FROM students stu
LEFT JOIN (
SELECT s_f.id, SUM(f.category_id IN (10,13,15) + 2 * f.category_id IN (1,7,8)) weight_sum
FROM students s_f
JOIN flags f
ON f.student_id = s_f.id
AND f.category_id IN (1,7,8,10,13,15)
WHERE s_f.year_group = :year_group
GROUP BY s_f.id
) f_group
LEFT JOIN (
SELECT s_a.id, 3 * COUNT(*) weight_sum
FROM students s_a
JOIN alerts a
ON a.student_id = s_a.id
AND a.type = 'P'
WHERE s_a.year_group = :year_group
GROUP BY s_a.id
) a_group
LEFT JOIN (
SELECT s_s.id, COUNT(*) weight_sum
FROM students s_s
JOIN sanctions s
ON s.student_id = s_s.id
AND s.category_id = 1
WHERE s_s.year_group = :year_group
GROUP BY s_s.id
) s_group
WHERE stu.year_group = :year_group
ORDER BY points DESC
LIMIT 0, 20
BUT if you have full access to the DB I'd be putting those weights in the respective categories and types, which will simplify the logic.

Bookings system

This is the database schema:
CREATE TABLE `bookings` (
`id` int(2) NOT NULL,
`start` time NOT NULL,
`end` time NOT NULL
)
INSERT INTO `bookings` VALUES(1, '13:00:00', '14:30:00');
INSERT INTO `bookings` VALUES(2, '15:00:00', '16:00:00');
I tried to run the following query, to find the free times:
SELECT free_from, free_until
FROM (SELECT a.end AS free_from,
(SELECT MIN(c.start)
FROM bookings c
WHERE c.start>a.end
) as free_until
FROM bookings a
WHERE NOT EXISTS (SELECT 1
FROM bookings b
WHERE b.start BETWEEN a.end AND a.end + INTERVAL your_duration HOURS
) AND
a.end BETWEEN '10:00:00' AND '18:00:00'
) t
The output generated is:
free_from free_until
14:30:00 15:00:00
16:00:00 NULL
Why is there a NULL in the end? Please help me solve this problem. Expected output should be:
free_from free_until
10:00:00 13:00:00
14:30:00 15:00:00
16:00:00 18:00:00
try this:
first create table and insert records
CREATE TABLE bookings (
id int NOT NULL,
start time NOT NULL,
endtime time NOT NULL
)
INSERT INTO bookings VALUES(1, '13:00:00', '14:30:00');
INSERT INTO bookings VALUES(2, '15:00:00', '16:00:00');
then run this select query
SELECT free_from, free_until
FROM (SELECT a.endtime AS free_from,
(SELECT MIN(c.start)
FROM bookings c
WHERE c.start>a.endtime
) as free_until
FROM bookings a
WHERE a.endtime BETWEEN '10:00:00' AND '18:00:00'
) t where free_until IS NOT NULL;
Note: I changed your column end to endtime
The first row of your output corresponds to the following data set:
a:
1, '13:00:00', '14:30:00'
c:
1, '13:00:00', '14:30:00'
2, '15:00:00', '16:00:00'
for "free_until", c.start must be higher than a.end, which is satisfied for this data set.(for 2nd row of C)
The second row of your output corresponds to the following data set:
a:
2, '15:00:00', '16:00:00'
c:
1, '13:00:00', '14:30:00'
2, '15:00:00', '16:00:00'
for "free_until", c.start>a.end but as you can see, a.end is 16:00 here, and no c.start is higher than this.
that's why null
Modify a.end of the second row to 14:00 and you will not get null value. :D
modify the data in the table:
Delete everything from bookings, then
INSERT INTO `bookings` VALUES(1, '13:00:00', '14:30:00');
INSERT INTO `bookings` VALUES(2, '15:00:00', '14:00:00');

sql update int column based on previous int column

I have a basic table FoodSales in which there is 3 columns SaleForDay decimal (10,2), SalesToDate decimal (10,2), ItemOrder Int
the data is like so
SaleForDay|SalesToDate|ItemOrder
4.99|4.99|1
12.99||2
14.99||3
5.99||4
I'm trying to get the result
SaleForDay|SalesToDate|ItemOrder
4.99|4.99|1
12.99|17.98|2
14.99|32.97|3
5.99|38.96|4
The method here is SalesToDate = the previous itemorder SalesToDate + the Current SaleforDay value.
To help out.
CREATE TABLE #FruitSales
(
SaleForDay DECIMAL (10, 2),
SalesToDate DECIMAL (10, 2),
ItemOrder INT
);
INSERT INTO #FruitSales (SaleForDay, SalesToDate, ItemOrder)
VALUES ('4.99', '4.99', '1'),
('12.99', NULL, '2'),
('14.99', NULL, '3'),
('5.99', NULL, '4');
SELECT * FROM #FruitSales;
DROP TABLE #FruitSales;
Thanks for the help, i realize this is probably simple as pie.
CREATE TABLE #FruitSales
(
SaleForDay DECIMAL (10, 2),
SalesToDate DECIMAL (10, 2),
ItemOrder INT
);
INSERT INTO #FruitSales (SaleForDay, SalesToDate, ItemOrder)
VALUES ('4.99', '4.99', '1'),
('12.99', NULL, '2'),
('14.99', NULL, '3'),
('5.99', NULL, '4');
update f
SET SalesToDate = (select sum(saleforday) from #FruitSales ff where ff.itemorder <= f.itemorder)
from #FruitSales f
SELECT * FROM #FruitSales;
Try this:
;WITH CumulativeData AS
(
SELECT b.ItemOrder, SUM(a.SaleForDay) AS TotalSales
FROM #FruitSales a INNER JOIN #FruitSales b
ON a.ItemOrder <= b.ItemOrder
GROUP BY b.ItemOrder
)
UPDATE a
SET a.SalesToDate = TotalSales
FROM #FruitSales a INNER JOIN CumulativeData b
ON a.ItemOrder = b.ItemOrder;
Another alternative:
UPDATE a
SET SalesToDate = TotalSales
FROM #FruitSales a CROSS APPLY
(SELECT SUM(SaleForDay) TotalSales FROM #FruitSales b WHERE b.ItemOrder <= a.ItemOrder) b