MySQL update field based on conditional sum from other table - mysql

I am trying to populate an attendance system with values from a legacy system.
I am currently tracking all_time attendance (which is simple), attendance in this year, and attendance since last grading (examination). To avoid potential contamination, I am storing legacy data, and want to import it into my totals a bit at a time.
This is my basic data model:
-- information about the attendee
CREATE TABLE core_member (
id INT UNSIGNED AUTO_INCREMENT,
name VARCHAR (250),
dob DATE,
last_grade_date date default '2014-12-14',
grade INT UNSIGNED NOT NULL DEFAULT 50,
PRIMARY KEY (id)
);
-- attendee data
INSERT INTO core_member values(1, 'Donald Duck', '1950-03-01', '2015-06-15', 10);
INSERT INTO core_member values(2, 'Goofy', '1950-04-17', '2014-06-15', 42);
-- attendance sums (1:1 with antendee)
CREATE TABLE core_attendance(
medlemsid INT UNSIGNED,
imported INT DEFAULT 0,
all_time INT DEFAULT 0,
since_last_grad INT DEFAULT 0,
UNIQUE KEY medlemsid (medlemsid),
FOREIGN KEY (medlemsid) REFERENCES core_member (id)
);
-- attendance sum data
INSERT INTO core_attendance values(1,100,150,0);
INSERT INTO core_attendance values(2,80,103,3);
-- historic attendance
CREATE TABLE core_historic_attendance (
medlemsid int(10) unsigned NOT NULL,
year int(11) NOT NULL,
month enum('none','januar','februar','marts','april','maj','juni','juli','august','september','oktober','november','december') NOT NULL DEFAULT 'none',
attendance int(11) DEFAULT '0',
UNIQUE KEY unq (medlemsid,year,month),
KEY medlemsid_idx (medlemsid),
CONSTRAINT medlemsid FOREIGN KEY (medlemsid) REFERENCES core_member (id) ON DELETE NO ACTION ON UPDATE NO ACTION
);
-- historic attendance data
INSERT INTO core_historic_attendance values(1,2011,'none',54);
INSERT INTO core_historic_attendance values(1,2012,'none',43);
INSERT INTO core_historic_attendance values(1,2013,'none',61);
INSERT INTO core_historic_attendance values(1,2014,'none',49);
INSERT INTO core_historic_attendance values(1,2015,'januar',19);
INSERT INTO core_historic_attendance values(1,2015,'februar',14);
INSERT INTO core_historic_attendance values(1,2015,'marts',17);
INSERT INTO core_historic_attendance values(2,2011,'none',54);
INSERT INTO core_historic_attendance values(2,2012,'none',43);
INSERT INTO core_historic_attendance values(2,2013,'none',61);
INSERT INTO core_historic_attendance values(2,2014,'none',49);
INSERT INTO core_historic_attendance values(2,2015,'januar',19);
INSERT INTO core_historic_attendance values(2,2015,'februar',4);
INSERT INTO core_historic_attendance values(2,2015,'marts',7);
I need to add the sum of all the values from core_historic attendance where the year is greater than the year of the last grading to the since_last_grad column in the core_member table, for the member in question (initial load).
I gather from this post ( mysql update column with value from another table ), that I have to do something like
UPDATE core_members INNER JOIN core_historic_attendance ON id = core_historic_attendance.medlemsid having`year` > year(last_grad_date)
SET since_last_grad = since_last_grad + SUM(attendance);
But I'm a bit stuck, since i want only the sum of the core_historic_attendance records where the year is greater than year(last_grad_date)
EDIT:
I have corrected the SQL as suggested by Sasha, nut I get an error code 1111 "Invalid use of group function"
I have created an SQL Fiddle as well

Does this work for you:
CREATE TEMPORARY TABLE t1 (key(medlemsid)) SELECT core_historic_attendance.medlemsid,SUM(attendance) as total_attendance
FROM core_member INNER JOIN core_historic_attendance ON
id = core_historic_attendance.medlemsid AND `year` > year(last_grade_date)
GROUP BY medlemsid;
UPDATE core_attendance INNER JOIN t1 USING(medlemsid)
SET since_last_grad = since_last_grad + t1.total_attendance;
?

Related

Update Table from Trigger

I have the following tables in a database:
CREATE TABLE `CRUISE-RES` (
`cruiseid` INT,
`end-day` DATE,
`start-day` DATE
PRIMARY KEY (`cruiseid`));
CREATE TABLE `ROOM` (
`cruise-id` INT,
`price` FLOAT,
FOREIGN KEY (`cruise-id`));
CREATE TABLE `PROFIT` (
`cruiseid` INT,
`total` FLOAT);
With the following sample table inserts:
-- cruise table inserts
insert into `CRUISE-ID` (`cruiseid`,`start-day`,`end-day`)
values (1, '2022/01/01', '2022/01/05'), (1, '2022/01/05', '2022/01/10'), (2, '2022/01/05', '2022/01/10')
-- room table inserts
insert into ROOM (price,`cruise-id`)
values (5,1), (10,1), (25,2)
I also have the following function that shows the profit of each cruiseid based on the number of days in the CRUISE-RES * price per day.
SELECT c.`cruiseid`, sum(rm.`price`*(DATEDIFF(c.`end-date`, c.`start-date`))) AS 'total_profit'
FROM ROOM rm
JOIN `CRUISE-RES` c
ON rm.`cruise-id` = c.cruiseid
GROUP BY rm.`cruise-id`,'cruiseid'
How can I use this information on a trigger that updates the PROFIT table after each insert into CRUISE-RES table?

sql how to use select query to get invoke foreign key

i was wondering how do i use the select query to Retrieve all offers of a listing.
Any tips or help to improve my codes is appreciated to! Thank you and have a nice day!
CREATE DATABASE IF NOT EXISTS `assignment_db`;
USE `assignment_db`;
CREATE TABLE USER_LIST(
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
userName VARCHAR(50) NOT NULL,
email varchar(100) NOT NULL,
registeredDate timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create table listing_list(
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
itemName VARCHAR(50) NOT NULL,
itemDescription VARCHAR(254) NOT NULL,
price DECIMAL(4,2) NOT NULL,
fk_poster_id int references USER_LIST(id),
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
create table offer_list(
id int(6) Unsigned auto_increment Primary key,
offer int,
fk_listing_id int references listing_list(id),
fk_offeror_id int references user_list(id),
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
);
insert into user_list (userName, email) values ('John','johnnyboi#123.com');
insert into user_list (userName, email) values ('Tom','Tommyboi#123.com');
insert into listing_list (itemName,itemDescription, price) values ( 'Pen', 'A long delicate pen.',' 1.50 ');
insert into listing_list (itemName,itemDescription, price) values ( 'Pencil', 'A long delicate pencil.',' 0.50 ');
insert into offer_list (offer,fk_listing_id,fk_offeror_id) values ('200','2','3');
insert into offer_list (offer,fk_listing_id,fk_offeror_id) values ('200','1','1');
All offer listing for existing user :
select a.*,b.*,c.* from offer_list a
INNER JOIN (listing_list as b)
on a.fk_listing_id=b.Id
INNER JOIN (user_list as c)
on a.fk_offeror_id=c.Id
just all offer listing :
select a.*,b.* from listing_list b
INNER JOIN (offer_list as a)
on a.fk_listing_id=b.Id
just all offer listing 2nd way
select a.*,b.* from offer_list a
INNER JOIN (listing_list as b)
on a.fk_listing_id=b.Id
Check it here , i tested them in this FIDDLE

How to make a certain set of values available in just one row

I would like to set up a database for a example project I have. I have chosen a driving school and work with tables including teachers, pupils, cars, time_lessons and bookings. The code can be seen in the code section. The four first tables i.e. teachers, pupils, cars and time_lessons are all foreign keys in bookings.
My issue is that I need certian combinations of these foreign keys to be available once. Let me clarify:
- A teacher cannot teach a same time_lessons twice
- A pupil cannot drive in a driving time_lessons twice
- A car cannot be used during the same time_lessons twice
- However a time in time_lessons can be used multiple times providing you have a pupil, a teacher and a car that haven't already been booked in that time.
How do I set this up?
See code below to see what I've done so far...
DROP DATABASE IF EXISTS c4trafik;
CREATE DATABASE c4trafik;
USE c4trafik;
CREATE TABLE teachers(
id INT PRIMARY KEY AUTO_INCREMENT,
t_fname VARCHAR(20) NOT NULL,
t_lname VARCHAR(20) NOT NULL,
auth_lvl INT DEFAULT 3
);
CREATE TABLE pupils(
id INT PRIMARY KEY AUTO_INCREMENT,
p_fname VARCHAR(20) NOT NULL,
p_lname VARCHAR(20) NOT NULL,
persnr CHAR(10) NOT NULL,
email VARCHAR(50) DEFAULT NULL,
telnr VARCHAR(10) DEFAULT NULL,
to_pay INT DEFAULT 0,
has_pay INT DEFAULT 0
);
CREATE TABLE cars(
id INT PRIMARY KEY AUTO_INCREMENT,
regnr VARCHAR(6) NOT NULL,
auto_gear BOOLEAN DEFAULT false
);
CREATE TABLE time_lessons(
id INT PRIMARY KEY AUTO_INCREMENT,
t_start TIMESTAMP NOT NULL,
t_end TIMESTAMP NOT NULL,
les_type VARCHAR(20) DEFAULT 'Driving Lesson'
);
CREATE TABLE bookings(
teachers_id INTEGER NOT NULL,
pupils_id INTEGER NOT NULL,
cars_id INTEGER NOT NULL,
time_lessons_id INTEGER NOT NULL,
FOREIGN KEY(teachers_id) REFERENCES teachers(id),
FOREIGN KEY(pupils_id) REFERENCES pupils(id) ON DELETE CASCADE,
FOREIGN KEY(cars_id) REFERENCES cars(id),
FOREIGN KEY(time_lessons_id) REFERENCES time_lessons(id) ON DELETE CASCADE,
PRIMARY KEY(teachers_id, pupils_id, cars_id, time_lessons_id)
);
INSERT INTO teachers (t_fname, t_lname, auth_lvl) VALUES
('Ali', 'Alisson', 1),
('Adam', 'Adamsson', 2),
('Noah', 'Noahsson', 3);
INSERT INTO pupils(p_fname, p_lname, persnr, email, telnr, to_pay, has_pay) VALUES
('Jakob', 'Jaboksson', '8702111254', 'pupil1#gmail.com','0704585962', 2800, 2800),
('Hassan','Hassansson', '9504234858' ,NULL,'0704125463',5000,1000),
('Mona','Monasson', '9410118547',NULL, NULL, 10200, NULL);
INSERT INTO cars (regnr, auto_gear) VALUES
('MNS111', false),
('OJS111', true),
('MNF111', false);
INSERT INTO time_lessons (t_start, t_end ) VALUES
('2019-06-10 08:00:00', '2019-06-10 08:40:00'),
('2019-06-10 08:50:00', '2019-06-10 09:30:00'),
('2019-06-10 09:40:00', '2019-06-10 10:20:00'),
('2019-06-10 10:30:00', '2019-06-10 11:10:00'),
('2019-06-10 11:20:00', '2019-06-10 12:00:00'),
('2019-06-10 13:10:00', '2019-06-10 13:50:00'),
('2019-06-10 14:00:00', '2019-06-10 14:40:00'),
('2019-06-10 14:50:00', '2019-06-10 15:30:00'),
('2019-06-10 15:40:00', '2019-06-10 16:20:00');
INSERT INTO bookings(teachers_id ,pupils_id, cars_id, time_lessons_id) VALUES
(1,2,1,1),(2,1,1,1),
(1,2,1,2),(2,1,2,2),
(1,1,1,3),(2,2,1,3);
-- Ska ge error om man duplicerar!!
-- Find main admin
SELECT t_fname, t_lname FROM teachers WHERE auth_lvl = 1;
-- How many manual geared cars?
SELECT COUNT(*) AS manually_geared FROM cars
WHERE auto_gear = false;
-- all booked student
SELECT p_fname, p_lname FROM bookings
INNER JOIN pupils ON pupils.id = bookings.pupils_id
GROUP BY p_lname, p_fname;
-- What time will each student drive?
SELECT p_fname, p_lname, t_start, t_end FROM bookings
INNER JOIN pupils ON pupils.id = bookings.pupils_id
INNER JOIN time_lessons ON time_lessons.id = bookings.time_lessons_id
ORDER BY p_lname, p_fname, t_start;
-- All time_lessons for teacher number 1
SELECT t_fname, p_fname, p_lname, t_start, t_end FROM bookings
INNER JOIN teachers ON teachers.id = bookings.teachers_id
INNER JOIN pupils ON pupils.id = bookings.pupils_id
INNER JOIN time_lessons ON time_lessons.id = bookings.time_lessons_id
WHERE teachers.id = 1;
So what I'm wondering is do I change my structure? Am I missing some code to make what I mentioned above work.
A teacher cannot teach a same time_lessons twice
Add a UNIQUE constraint on the (teacher_id,time_lesson_id) tuple in the booking, e.g.
CREATE UNIQUE INDEX booking_UX1 ON booking (teacher_id,time_lesson_id)
This will disallow rows with duplicates of a combination of values. If an attempt to INSERT a new row (or UPDATE and existing row) would cause two rows to have the same values, the statement will fail with error 1062 "Duplicate entry '' for key ".
A pupil cannot drive in a driving time_lessons twice
A UNIQUE index will prevent duplicates:
CREATE UNIQUE INDEX booking_UX2 ON booking (pupil_id,time_lesson_id)
(My preference is for entity tables be named in the singular, to name what one row represents.)

Taking the most commonly occuring (modal) value for several columns

I am cleaning records that have poorly recorded and inconsistent socio-demographic information over time, for the same person. I want to take the most commonly occuring value (the mode) for each person.
One way to do that is to partition by id and then count how many times each value occurs, retaining the highest count for each id:
DROP TABLE dbo.table
SELECT DISTINCT [id], [ethnic_group] AS [ethnic_mode], ct INTO dbo.table
FROM (
SELECT row_number() OVER (PARTITION BY [id] ORDER BY count([ethnic_group]) DESC) as rn, count([ethnic_group]) as ct, [ethnic_group], [id]
FROM
dbo.mytable GROUP BY [id], [ethnic_group]) ranked
where rn = 1
ORDER BY ct DESC
But I want to do this for several variables (ethnic group, income group and several more).
How can I select the mode for several variables within one statement and insert into one table (rather than creating separate tables for each variable)?
The table below illustrates an example of what I want to do:
DROP TABLE mytable;
CREATE TABLE mytable(
id VARCHAR(2) NOT NULL PRIMARY KEY
,ethnic_group VARCHAR(12) NOT NULL
,ethnic_mode VARCHAR(11) NOT NULL
,income VARCHAR(6) NOT NULL
,income_mode VARCHAR(11) NOT NULL
);
INSERT INTO mytable(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('id','ethnic_group','ethnic_mode','income','income_mode');
INSERT INTO mytable(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('1','white','white','middle','middle');
INSERT INTO mytable(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('1','white','white','middle','middle');
INSERT INTO mytable(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('1','mixed','white','high','middle');
INSERT INTO mytable(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('2','asian','asian','middle','middle');
INSERT INTO mytable(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('2','mixed','asian','middle','middle');
INSERT INTO mytable(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('2','asian','asian','middle','middle');
I would use sub-queries to accomplish this in 1 insert statement.
Here is an example based on the table structure from your illustration:
/* This is the original table and contains duplicate ID's */
DECLARE #source_table TABLE(
id VARCHAR(2) NOT NULL
,ethnic_group VARCHAR(12) NULL
,ethnic_mode VARCHAR(11) NULL
,income VARCHAR(6) NULL
,income_mode VARCHAR(11) NULL
);
/* This is the destination table and will not contain duplicate ID's */
DECLARE #destination_table TABLE(
id VARCHAR(2) NOT NULL PRIMARY KEY
,ethnic_group VARCHAR(12) NULL
,income VARCHAR(6) NULL
);
/* Populate the source table with data */
INSERT INTO #source_table(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('1','white','white','middle','middle');
INSERT INTO #source_table(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('1','white','white','middle','middle');
INSERT INTO #source_table(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('1','mixed','white','high','middle');
INSERT INTO #source_table(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('2','asian','asian','middle','middle');
INSERT INTO #source_table(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('2','mixed','asian','middle','middle');
INSERT INTO #source_table(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('2','asian','asian','middle','middle');
INSERT INTO #source_table(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('3','asian', NULL, NULL, NULL);
INSERT INTO #source_table(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('3',NULL, NULL,'middle', NULL);
INSERT INTO #source_table(id,ethnic_group,ethnic_mode,income,income_mode) VALUES ('3',NULL, NULL, NULL, NULL);
/* Insert from source into destination (removing duplicates) */
INSERT INTO #destination_table
(
id
, ethnic_group
, income
)
SELECT st.id
, (
SELECT TOP 1 ethnic_group
FROM #source_table sub_st
WHERE sub_st.id = st.id
GROUP BY ethnic_group
ORDER BY COUNT(sub_st.id) DESC
)
, (
SELECT TOP 1 income
FROM #source_table sub_st
WHERE sub_st.id = st.id
GROUP BY income
ORDER BY COUNT(sub_st.id) DESC
)
FROM #source_table st
GROUP BY st.id
/* View the destination to see there are no duplicates */
SELECT id
, ethnic_group
, income
FROM #destination_table

How implementation my wants with MySQL JOIN

_
Hello everyone!
I have table
CREATE TABLE `labels` (
`id` INT NULL AUTO_INCREMENT DEFAULT NULL,
`name` VARCHAR(250) NULL DEFAULT NULL,
`score` INT NULL DEFAULT NULL,
`before_score` INT NULL DEFAULT NULL,
PRIMARY KEY (`id`)
);
And I Have This Table
CREATE TABLE `scores` (
`id` INT NULL AUTO_INCREMENT DEFAULT NULL,
`name_id` INT NULL DEFAULT NULL,
`score` INT NULL DEFAULT NULL,
`date` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`)
);
And i want have result where labels.score - have value last scores.score sorted by scores.date and labels.before_score where have value penultimate scores.score sorted by scores.date. Can I do This Only on Mysql slq and how?
Thanks.
ADD
For example i have this data on first table:
INSERT INTO `labels` (id, name, score, before_score) VALUES (1, 'John', 200, 123);
INSERT INTO `labels` (id, name, score, before_score) VALUES (2, 'Eddie', 2000, 2000);
INSERT INTO `labels` (id, name, score, before_score) VALUES (3, 'Bob', 400, 3101);
And second table
INSERT INTO `scores` (`id`,`name_id`,`score`,`date`) VALUES ('1','1','12','2013-07-10');
INSERT INTO `scores` (`id`,`name_id`,`score`,`date`) VALUES ('2','2','2000','2013-05-04');
INSERT INTO `scores` (`id`,`name_id`,`score`,`date`) VALUES ('3','3','654','2012-09-12');
INSERT INTO `scores` (`id`,`name_id`,`score`,`date`) VALUES ('4','1','123','2013-12-17');
INSERT INTO `scores` (`id`,`name_id`,`score`,`date`) VALUES ('5','1','200','2014-04-25');
INSERT INTO `scores` (`id`,`name_id`,`score`,`date`) VALUES ('6','3','3101','2013-12-02');
INSERT INTO `scores` (`id`,`name_id`,`score`,`date`) VALUES ('6','2','2000','2015-12-02');
INSERT INTO `scores` (`id`,`name_id`,`score`,`date`) VALUES ('6','3','400','2013-12-02');
If I understand correctly, you need the last two scores for each name_id.
I would tackle this with temporary tables:
Step 1. Last score:
create temporary table temp_score1
select name_id, max(`date`) as lastDate
from scores
group by name_id;
-- Add the appropriate indexes
alter table temp_score1
add unique index idx_name_id(name_id),
add index idx_lastDate(lastDate);
Step 2. Penultimate score. The idea is exactly the same, but using temp_score1 to filter the data:
create temporary table temp_score2
select s.name_id, max(`date`) as penultimateDate
from scores as s
inner join temp_score1 as t on s.nameId = t.nameId
where s.`date` < t.lastDate
group by name_id;
-- Add the appropriate indexes
alter table temp_score2
add unique index idx_name_id(name_id),
add index idx_penultimateDate(penultimateDate);
Step 3. Put it all together.
select
l.id, l.name,
s1.lastScore, s2.penultimateScore
from
`labels` as l
left join temp_score1 as s1 on l.id = s1.name_id
left join temp_score2 as s2 on l.id = s2.name_id
You can put this three steps inside a stored procedure.
Hope this helps you.