MYSQL aggregate entries when joined fields have multiple matches - mysql

I am trying to count total answers, and total correct responses to a given question for students who might be enrolled in multiple classes with a given teacher. I would like the results grouped by test and teacher, with duplicate students removed.
What I would like to get out of the following is:
test1-teacher1-6-4
test1-teacher2-3-2
However, the fact that student3, student4 and student5 are enrolled in different classes with teacher1 (see below) is causing them to be counted twice, so I get...
test1-teacher1-6-6
test1-teacher2-3-2
Here is all the data I am using.
Any thoughts on how to remove the duplicate students? Thanks.
create database test_db;
use test_db;
drop table if exists test;
create table test(test_name varchar (50),student_name varchar(50),result varchar(50));
drop table if exists roster;
create table roster(teacher_name varchar(50),student_name varchar(50), class_name varchar(50));
insert into test values ('test1','student1','c');
insert into test values ('test1','student2','x');
insert into test values ('test1','student3','x');
insert into test values ('test1','student4','c');
insert into test values ('test1','student5','c');
insert into test values ('test1','student6','c');
insert into test values ('test1','student7','c');
insert into test values ('test1','student8','x');
insert into roster values ('teacher1', 'student1', 'class1');
insert into roster values ('teacher1', 'student2', 'class1');
insert into roster values ('teacher1', 'student3', 'class1');
insert into roster values ('teacher1', 'student4', 'class1');
insert into roster values ('teacher1', 'student5', 'class1');
insert into roster values ('teacher1', 'student6', 'class1');
insert into roster values ('teacher1', 'student3', 'class2');
insert into roster values ('teacher1', 'student4', 'class2');
insert into roster values ('teacher1', 'student5', 'class2');
insert into roster values ('teacher2', 'student6', 'class3');
insert into roster values ('teacher2', 'student7', 'class3');
insert into roster values ('teacher2', 'student8', 'class3');
use test_db;
select
test_name,
r.teacher_name,
count(distinct r.student_name) as numTested,
sum(case
when result = 'c' then 1
else null
end) as Q1correct
from
test t
join
roster r ON t.student_name = r.student_name
group by t.test_name , r.teacher_name;

Use a sub-query to remove the duplicates from roster.
select
test_name,
r.teacher_name,
count(distinct r.student_name) as numTested,
sum(case
when result = 'c' then 1
else null
end) as Q1correct
from
test t
join
(select distinct teacher_name, student_name
from roster) r ON t.student_name = r.student_name
group by t.test_name , r.teacher_name;
SQLFIDDLE

Related

MySQL if exists insert id else insert into two tables

I've made the following SQL statement and it does not work and cannot figure out how to create a functioning one. Here is what i am trying to do.
Check if a value exists in a players table
If the value exists, i want to insert ignore into a roster table
If the value doesnt exist, i want to insert it into the players table and insert it into the roster table
Here is what i have
IF EXISTS (SELECT id AS plyrId FROM players WHERE email = #(:e) LIMIT 1)
BEGIN
INSERT IGNORE INTO roster
(date, teamId, playerId)
VALUES
( (:d), (:t), plyrId )
END
ELSE
BEGIN
INSERT INTO players
(status, date, first_name, last_name, email)
VALUES
( (:s), (:d), (:f), (:l), (:e) )
INSERT IGNORE INTO roster
(date, teamId, playerId)
VALUES
( (:d), (:t), LAST_INSERT_ID() ) //LAST_INSERT_ID() -> I want it to be pulled from the last id inserted from the players table - not sure how to accomplish this
END
Any help is appreciated!
ive tried another attemp without any luck either
IF (SELECT COUNT(*) FROM players WHERE email = (:e) > 0)
INSERT IGNORE INTO roster
(date, teamId, playerId)
(:d), (:t), SELECT id FROM players WHERE email =(:e)
ELSE
BEGIN
.. // havent got to this part yet. it follows the same logic as the one before
END
You must use trigger on event before insert
CREATE TRIGGER test_trigger BEFORE INSERT ON `players table` FOR EACH ROW SET
-- checking value exist or not, for each case write corresponding insert or inserts
This part of the query is highly suspect:
IF EXISTS (SELECT id AS plyrId FROM players WHERE email = #(:e) LIMIT 1)
BEGIN
INSERT IGNORE INTO roster
(date, teamId, playerId)
VALUES
( (:d), (:t), plyrId )
----------------------^
END
Unless you have a variable named plyrId, this will fail. Assigning an alias in a subquery does not define a variable in the outer query.
You can replace it with:
INSERT IGNORE INTO roster(date, teamId, playerId)
SELECT (:d), (:t), id
FROM players
WHERE email = #(:e)
LIMIT 1;
Or, you can change the if to:
IF EXISTS (SELECT plyrdId := id FROM players WHERE email = #(:e) LIMIT 1)

Can an auto-incremented value in MySQL be preserved?

How do I preserve the last_insert_id() into a specific record?
Here are my queries:
INSERT INTO student(student_name) VALUES ('ramgopal')`;
SELECT `last_insert_id()`;
INSERT INTO grades (student_id,grade) VALUES (last_insert_id(),'A');
INSERT INTO class (semester,day,time) VALUES ('spring 2015','tuesday','12');
SELECT last_insert_id();
insert INTO grades(class_id) VALUES (last_insert_id());
In grade table I got grade_id, class_id, student_id and grade records.
When I use the last_insert_id() again it is just inserting the latest id and the previous id is not inserting. So I would like to preserve the initial last_insert_id for further use.

Insert into table if a field value do not already exist

I want to insert values to a row in my customer table if the Name value I'm providing do not already exist,
After some searching I used this sql query to do it and it does not work :(
IF NOT EXISTS (SELECT Name FROM customer WHERE Name = 'Riyafa')
INSERT INTO customer (`Name`, `Address`, `ContactNo`,`Total_amout`)
VALUES ('Riyafa', 'ABC', '555','1000');
Please instruct me why that is incorrect.
The if statement is only allowed in stored procedures, functions, and triggers. One way you can do this is:
INSERT INTO customer (`Name`, `Address`, `ContactNo`,`Total_amout`)
SELECT name, address, contactno, total_amount
FROM (SELECT 'Riyafa' as name, 'ABC' as address, '555' as contact no, '1000' as total_amount) t
WHERE NOT EXISTS (SELECT 1 FROM customer c WHERE c.name = t.name);
A better approach, however, is to have the database enforce uniqueness on the name. Start by creating a unique index or name:
CREATE UNIQUE INDEX idx_customer_name ON customer(name);
Then use a construct such as on duplicate key update:
INSERT INTO customer (`Name`, `Address`, `ContactNo`,`Total_amout`)
SELECT 'Riyafa' as name, 'ABC' as address, '555' as contact no, '1000' as total_amount
ON DUPLICATE KEY UPDATE Name = VALUES(Name);
The expression ON DUPLICATE KEY UPDATE Name = VALUES(Name) actually doesn't do anything, but it prevents the INSERT from returning an error.

How to use procedure variable in select and insert query in MySQL?

I have two variables
1. inserted_user_id,
2. inserted_address_id
in my MySQL procedure.
I need to use them in insert queries and select queries. Im trying something like
insert into user_new(name, company, email, customer_id) select name,
company, email, inserted_user_id from user_old;
insert into user_address_map(address_id, user_id) select
inserted_user_id,inserted_address_id ;
There two statements are not working. How to use procedure variable's value in the above sql statements?
First make a select to get all the info: (you need to declare these variables first)
SELECT name,
company,
email,
INTO varname, varcompany, varemail
FROM user_old
then use it into insert
INSERT INTO user_new
(name,
company,
email,
customer_id)
VALUES (varname,
varcompany,
varemail,
inserted_user_id);
edit:
First insert the Selected values and get the id of the inserted row
INSERT INTO user_new
(name,
company,
email)
SELECT name,
company,
email
FROM user_old
SET out_param = last_insert_id();
Then update this row with your param
UPDATE user_new
SET customer_id = inserted_user_id
WHERE id = out_param;

2 Dates from the same column in one SQL query

I'm trying to work out an average between of time between two dates in the same field.
Basically i've got a transaction date and an id for each transaction and a customer id for each transaction.
I need to get the time between the first transaction and the second transaction. I dont mind working out the average between the two in excel but I dont know how to pull two dates from the same field.
transaction.created_at of the first transaction minus transaction.created_at of the second transaction for each and every customer in the database. I can pull the date of a transaction like
select
customer.id,
transaction.created_at
count(transaction.id)
from transaction
having count(transaction.id) = 2
Thanks
Not sure if this will always be Having count(*) = 2? If so, I think you could just use min and max, no?
/*
create table dbo.Example (tran_id int,created_at datetime,cust_id int)
insert dbo.example values (1,'10/1/2012',900)
insert dbo.example values (2,'10/2/2012',901)
insert dbo.example values (3,'10/18/2012',590)
insert dbo.example values (4,'10/10/2012',676)
insert dbo.example values (5,'10/11/2012',123)
insert dbo.example values (6,'10/17/2012',456)
insert dbo.example values (7,'10/9/2012',901)
insert dbo.example values (8,'10/30/2012',900)
insert dbo.example values (9,'10/4/2012',456)
insert dbo.example values (10,'10/17/2012',676)
*/
select
cust_id,
max([created_at]) as [Last Date],
min([created_at]) as [First Date],
datediff(hh,min([created_at]) ,max([created_at])) as [Hours diff]
from example
group by cust_id
having count(*) = 2
order by cust_id
Try the following to retrieve particular customer transactions count:
Select
Customer.id,
count(transaction.id)
from transaction
where Customer.id = '10'
Here 10 specifies the customer id that has been searched by you. You have to pass this customer id as parameter in your created SP.