I have a table as follows for tracking employee daily entry. An employee can has multiple check in and out a day.
Is there a way to display in a way such that each record has the EmployeeID and respective earliest CheckIn and latest CheckOut of each day to summarize the record.
CREATE TABLE IF NOT EXISTS `PhyMeS_schema`.`DailyEntry` (
`EmployeeID` VARCHAR(10) NOT NULL,
`CheckIn` DATETIME NOT NULL,
`CheckOut` DATETIME NULL,
PRIMARY KEY (`EmployeeID`, `CheckIn`),
CONSTRAINT `fk_dailyEntry_EmployeeID`
FOREIGN KEY (`EmployeeID`)
REFERENCES `PhyMeS_schema`.`Employee` (`EmployeeID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
You should be able to do this with a simple GROUP BY on EmployeeID and DATE(CheckIn), like this:
SELECT
EmployeeID
, DATE(CheckIn) AS the_date
, MIN(CheckIn) AS min_checkin
, MAX(CheckOut) AS max_checkout
FROM DailyEntry
GROUP BY EmployeeID, DATE(CheckIn)
Note: this query assumes that all checkouts happen on the same day as their corresponding check-ins. In other words, nobody is inside on midnight. If you need to deal with night shifts, the query becomes more complex:
SELECT EmployeeID, the_date, MIN(min_checkin), MAX(max_checkout)
FROM (
SELECT EmployeeID, DATE(CheckIn) AS the_date, MIN(CheckIn) AS min_checkin, null as max_checkout
FROM DailyEntry
GROUP BY EmployeeID, DATE(CheckIn)
UNION ALL
SELECT EmployeeID, DATE(CheckOut) AS the_date, null AS min_checkin, MAX(CheckOut) as max_checkout
FROM DailyEntry
GROUP BY EmployeeID, DATE(CheckOut)
) GROUP BY EmployeeID, the_date
Related
I'm looking for a way to create a query that gives me the list of people who were born on the same day (the data is in two different tables).
All ideas are welcome. ( I use MySQL)
SQL code :
https://pastebin.com/StNggaYg
CREATE TABLE Professeurs(
ID_Professeur Int Auto_increment NOT NULL ,
Nom_Professeur Varchar (50) NOT NULL ,
Prenom_Professeur Varchar (50) NOT NULL ,
Ville_de_naissance_P Varchar (50) NOT NULL ,
Date_de_naissance_P Date NOT NULL ,
Professeur_Principal Bool NOT NULL
,CONSTRAINT Professeurs_PK PRIMARY KEY (ID_Professeur)
)ENGINE=InnoDB;
#------------------------------------------------------------
# Table: Classes
#------------------------------------------------------------
CREATE TABLE Classes(
ID_Classes Int Auto_increment NOT NULL ,
Lettre_classe Char (5) NOT NULL ,
ID_Professeur Int NOT NULL
,CONSTRAINT Classes_PK PRIMARY KEY (ID_Classes)
,CONSTRAINT Classes_Professeurs_FK FOREIGN KEY (ID_Professeur) REFERENCES Professeurs(ID_Professeur)
)ENGINE=InnoDB;
#------------------------------------------------------------
# Table: Elèves
#------------------------------------------------------------
CREATE TABLE Eleves(
ID_Eleve Int Auto_increment NOT NULL ,
Nom_eleve Varchar (50) NOT NULL ,
Prenom_eleve Varchar (50) NOT NULL ,
Ville_de_naissance_E Varchar (50) NOT NULL ,
Date_de_naissance_E Date NOT NULL ,
ID_Classes Int NOT NULL
,CONSTRAINT Eleves_PK PRIMARY KEY (ID_Eleve)
,CONSTRAINT Eleves_Classes_FK FOREIGN KEY (ID_Classes) REFERENCES Classes(ID_Classes)
)ENGINE=InnoDB;
The column :
Date_de_naissance_E Date NOT NULL ,
Date_de_naissance_P Date NOT NULL ,
First, you would have to get the results of BOTH tables dates via a UNION to find what dates have more than one instance. Its possible to have two teachers with same date, two students with same date, OR a teacher AND student have same date. Once that is done, then you can join back to the respective original source to grab the names.
To simplify the query from rewriting it twice nested within itself, I will use CTE (common table expression). It allows you to write a query that will be used multiple times allowing simple alias name to be used in a subsequent query.
Below is the CTE via "With AllPeople as". This select is the query used in the second half. Notice I am getting ID, name, birth date and also a type "P" as Professeur and "E" as Eleves for the person type. First time through I am getting a count where a given birthdate occurs more than once. THEN, re-join to the same AllPeople again that had that date found as a common birth date.
with AllPeople as
( select
'P' personType,
p.ID_Professeur personID,
p.Nom_Professeur personName,
Date_Format( p.Date_de_naissance_P, "%M %d" ) commonDate
from
Professeurs p
union all
select
'E' personType,
e.ID_Eleve personID,
e.nom_eleve personName,
Date_Format( e.Date_de_naissance_E, "%M %d" ) commonDate
from
Eleves e
)
select
who.PersonType,
who.PersonID,
who.PersonName,
BornOnSameDay.commonDate
from
(select
commonDate
from
AllPeople
group by
commonDate
having
count(*) > 1 ) BornOnSameDay
JOIN
AllPeople Who
on BornOnSameDay.commonDate = Who.commonDate
order by
BornOnSameDay.commonDate,
who.PersonName
Now, you also provided a class table of which teachers were teaching what class, and if a student was in a particular class. If your intention was to find out which classes has a student with the same birthdate as the professor teaching it, that would be a different query.
Please advise on which you meant. The one I have provided is ANY teacher having a same birthday as ANY other teacher OR student. And likewise could be two students having the same birth date.
You can use the GROUP_CONCAT function:
SELECT date_format(birthdate,"%d %b") AS birthday, GROUP_CONCAT(person_name) AS people
FROM persons
GROUP BY MONTH(birthdate), DATE(birthdate)
I'm struggling to create a view in SQL that will the total number of items a customer buys from the business in April 2019 along with the total price.
Here are my tables.
CREATE TABLE Customer (
CustID int AUTO_INCREMENT,
Fname varchar(50) NOT NULL,
Sname varchar(50) NOT NULL,
PRIMARY KEY (CustID)
);
CREATE TABLE Transaction (
TransID int AUTO_INCREMENT,
OrderDate date NOT NULL,
ArriveDate date NOT NULL,
CustID int,
PRIMARY KEY (TransID),
FOREIGN KEY (CustID) REFERENCES Customer(CustID)
);
CREATE TABLE TransactionDetails(
TranDetID int AUTO_INCREMENT NOT NULL,
quantity int NOT NULL,
price int NOT NULL,
TransID int,
PRIMARY KEY (TranDetID),
FOREIGN KEY (TransID) REFERENCES Transaction(TransID)
);
Hope this helps. you can change the year and month using the 1st 2 lines of code
DECLARE #Year INT = 2019,
#Month NVARCHAR(15) = 'April'
SELECT C.Fname, SUM(TD.quantity) AS quantity, SUM(TD.price) AS price
FROM [Transaction] T
LEFT JOIN customer C ON C.CustID = T.CustID
LEFT JOIN TransactionDetails TD ON TD.TransID = T.TransID
WHERE DATENAME(month, OrderDate) = #Month AND DATENAME(YEAR, OrderDate) = #Year
GROUP BY C.Fname
Seems curious, but:
select td.custid, sum(quantity) as total_quantity,
sum(price) as total_price. -- perhaps "price * quantity"???
from transactions t join
transactiondetails td
using (TransID)
where t.orderdate >= '2019-04-01' and t.orderdate < '2019-05-01';
This is curious because your data model does not distinguish between products, which I would expect. It is unclear whether the price needs to be multiplied by the quantity, because you have no sample data and desired results.
I have to insert a lot of rows to a table basic_data like this:
basic_data
customer | max_sale | total_sales
CREATE TABLE `basic_data` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`customer` int(11) NOT NULL ,
`total_sales` decimal(15,2) NOT NULL ,
`max_sale` tinyint(2) NOT NULL ,
PRIMARY KEY (`id`),
UNIQUE INDEX `customer` USING BTREE (`customer`)
)
As I get (customer, max_sale) and (customer, total_sales) in different queries, I would like to know if it is possible to fill the table so that one customer has just one row with both values max_sale and total_sales.
My insert queries are:
INSERT INTO
basic_data (customer, max_sale)
SELECT a.customer, a.max_sale
FROM sales a
....
GROUP BY customer;
INSERT INTO
basic_data (customer,total_value)
SELECT customer, SUM(sales) total_value
FROM sales a
GROUP BY customer;
And I have read I can use ON DUPLICATE KEY UPDATE but cannot manage to use it properly.
My attempts on
INSERT INTO
basic_data (customer,total_value)
SELECT customer, SUM(sales) total_value
FROM sales a
GROUP BY customer
ON DUPLICATE KEY person UPDATE total_value = ...
have been unsuccessful and I think it is because ON DUPLICATE KEY does not work with GROUP BY.
Any idea how to store data this way? Big thanks.
UPDATE 1
INSERT INTO basic_data (customer,total_value)
SELECT customer, total_value
FROM
(
SELECT customer, SUM(sales) total_value
FROM sales a
GROUP BY customer
) c
ON DUPLICATE KEY UPDATE total_value = c.total_value
I am trying to insert a new row and set the customer_id with max()+1. The reason for this is the table already has a auto_increatment on another column named id and the table will have multiple rows with the same customer_id.
With this:
INSERT INTO customers
( customer_id, firstname, surname )
VALUES
((SELECT MAX( customer_id ) FROM customers) +1, 'jim', 'sock')
...I keep getting the following error:
#1093 - You can't specify target table 'customers' for update in FROM clause
Also how would I stop 2 different customers being added at the same time and not having the same customer_id?
You can use the INSERT ... SELECT statement to get the MAX()+1 value and insert at the same time:
INSERT INTO
customers( customer_id, firstname, surname )
SELECT MAX( customer_id ) + 1, 'jim', 'sock' FROM customers;
Note: You need to drop the VALUES from your INSERT and make sure the SELECT selected fields match the INSERT declared fields.
Correct, you can not modify and select from the same table in the same query. You would have to perform the above in two separate queries.
The best way is to use a transaction but if your not using innodb tables then next best is locking the tables and then performing your queries. So:
Lock tables customers write;
$max = SELECT MAX( customer_id ) FROM customers;
Grab the max id and then perform the insert
INSERT INTO customers( customer_id, firstname, surname )
VALUES ($max+1 , 'jim', 'sock')
unlock tables;
Use alias name for the inner query like this
INSERT INTO customers
( customer_id, firstname, surname )
VALUES
((SELECT MAX( customer_id )+1 FROM customers cust), 'sharath', 'rock')
SELECT MAX(col) +1 is not safe -- it does not ensure that you aren't inserting more than one customer with the same customer_id value, regardless if selecting from the same table or any others. The proper way to ensure a unique integer value is assigned on insertion into your table in MySQL is to use AUTO_INCREMENT. The ANSI standard is to use sequences, but MySQL doesn't support them. An AUTO_INCREMENT column can only be defined in the CREATE TABLE statement:
CREATE TABLE `customers` (
`customer_id` int(11) NOT NULL AUTO_INCREMENT,
`firstname` varchar(45) DEFAULT NULL,
`surname` varchar(45) DEFAULT NULL,
PRIMARY KEY (`customer_id`)
)
That said, this worked fine for me on 5.1.49:
CREATE TABLE `customers` (
`customer_id` int(11) NOT NULL DEFAULT '0',
`firstname` varchar(45) DEFAULT NULL,
`surname` varchar(45) DEFAULT NULL,
PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$
INSERT INTO customers VALUES (1, 'a', 'b');
INSERT INTO customers
SELECT MAX(customer_id) + 1, 'jim', 'sock'
FROM CUSTOMERS;
insert into table1(id1) select (max(id1)+1) from table1;
Use table alias in subquery:
INSERT INTO customers
( customer_id, firstname, surname )
VALUES
((SELECT MAX( customer_id ) FROM customers C) +1, 'jim', 'sock')
None of the about answers works for my case. I got the answer from here, and my SQL is:
INSERT INTO product (id, catalog_id, status_id, name, measure_unit_id, description, create_time)
VALUES (
(SELECT id FROM (SELECT COALESCE(MAX(id),0)+1 AS id FROM product) AS temp),
(SELECT id FROM product_catalog WHERE name="AppSys1"),
(SELECT id FROM product_status WHERE name ="active"),
"prod_name_x",
(SELECT id FROM measure_unit WHERE name ="unit"),
"prod_description_y",
UNIX_TIMESTAMP(NOW())
)
Your sub-query is just incomplete, that's all. See the query below with my additions:
INSERT INTO customers ( customer_id, firstname, surname )
VALUES ((SELECT MAX( customer_id ) FROM customers) +1), 'jim', 'sock')
You can't do it in a single query, but you could do it within a transaction. Do the initial MAX() select and lock the table, then do the insert. The transaction ensures that nothing will interrupt the two queries, and the lock ensures that nothing else can try doing the same thing elsewhere at the same time.
We declare a variable 'a'
SET **#a** = (SELECT MAX( customer_id ) FROM customers) +1;
INSERT INTO customers
( customer_id, firstname, surname )
VALUES
(**#a**, 'jim', 'sock')
This is select come insert sequel.
I am trying to get serial_no maximum +1 value and its giving correct value.
SELECT MAX(serial_no)+1 into #var FROM sample.kettle;
Insert into kettle(serial_no,name,age,salary) values (#var,'aaa',23,2000);
rental table:
CREATE TABLE RENTAL
(
TransactionNo int NOT NULL AUTO_INCREMENT,
MemberID int NOT NULL,
ItemNo char(3) NOT NULL,
RentalEmployeeID varchar(30),
ReturnEmployeeID varchar(30),
Checkout_date DATE,
Checkin_date DATE,
Return_date DATE,
ItemQuantity int(11) NOT NULL,
TotalPrice DOUBLE(10,2) NOT NULL,
ItemFee DOUBLE(10,2),
PRIMARY KEY(TransactionNo),
FOREIGN KEY(MemberID) REFERENCES Member(MemberID),
FOREIGN KEY(ItemNo) REFERENCES Item(Itemno),
FOREIGN KEY(RENTALEMPLOYEEID) REFERENCES Employee(EmployeeID),
FOREIGN KEY(RETURNEMPLOYEEID) REFERENCES Employee(EmployeeID)
)
I am trying to retrieve the query for all of the customers that have purchased at least 2 items on the same day, however; i am still unable to accomplish it. Is a nested clause necessary for this?
my statement:
SELECT m.MemberID, r.`checkout_date`, SUM(r.itemquantity)
FROM RENTAL AS r, MEMBER AS m
WHERE r.MemberID = m.MemberID
GROUP BY m.MemberID, r.`checkout_date`
HAVING SUM (r.itemquantity) > 1
This new statement will give me what i want, however; because the rental information is not required(NULL) it sums up all of the return items as well and not the just rental.
You dont need a nested clause - 'GROUP BY' does the trick.
SELECT m.MemberID, r.`checkout_date`, COUNT(r.itemno)
FROM RENTAL AS r, MEMBER AS m
WHERE r.MemberID = m.MemberID
GROUP BY r.MemberID, `r.checkout_date`
group by memberid, checkoutdate having count(transactionid) > 1