Given the schema and data below,
CREATE TABLE `Payroll` (
`payId` int,
`payName` varchar(20),
`groupId` int,
`startDate` date ,
`endDate` date,
`paymentDate` date
);
insert into Payroll values
(20,'June A',2,'2022-06-01','2022-06-30','2022-06-30'),
(21,'July A',2,'2022-07-01','2022-07-31','2022-07-31'),
(17,'April A',1,'2022-04-01','2022-04-30','2022-04-30'),
(18,'May A',1,'2022-05-01','2022-05-31','2022-05-31'),
(19,'July B',1,'2022-07-01','2022-07-31','2022-07-31')
;
CREATE TABLE `PayrollItems` (
`payId` int NOT NULL,
`employeeId` int ,
`payCategory` varchar(45) ,
`value` decimal(15,4) NOT NULL
);
insert into PayrollItems values
(20,12,'salary',200),
(20,12,'housing',500),
(20,13,'salary',400),
(20,14,'salary',1300),
(21,12,'salary',200),
(21,12,'housing',500),
(21,13,'salary',400),
(21,14,'salary',1300),
(18,13,'salary',400),
(18,13,'housing',1300),
(19,14,'salary',500),
(19,14,'housing',1200),
(17,14,'salary',700),
(17,14,'housing',1000)
;
How should i enhance the below query so that i get the previous payid row only, previous pay id would be a payid that has the same group id but a payment date dated prior, having said that i would want the one payid dated prior.
SELECT distinct
a.payId,a.payName, b.*
FROM
(SELECT
Payroll.payId,
employeeId,
payName,
groupId,
paymentDate,
SUM(value * (payCategory = 'housing')) housing,
SUM(value * (payCategory = 'salary')) salary
FROM
PayrollItems
JOIN Payroll ON (Payroll.payid = PayrollItems.payId)
GROUP BY Payroll.payId , employeeId , groupId , paymentDate,payName) a
JOIN
(SELECT
Payroll.payId,
employeeId,
payName,
groupId,
max(paymentDate) paymentDate,
SUM(value * (payCategory = 'housing')) housing,
SUM(value * (payCategory = 'salary')) salary
FROM
PayrollItems
JOIN Payroll ON (Payroll.payid = PayrollItems.payId)
GROUP BY Payroll.payId , employeeId , groupId , paymentDate,payName) b ON b.groupId = a.groupId
AND b.paymentDate < a.paymentDate
order by a.payId,b.payId,b.employeeId
;
In the result shown below i do not need the row marked in red to appear
dbfiddle
I think you need to learn how to use MySQL 8.0 window functions.
mysql> select payId, lag(payId) over (partition by groupId order by payId) as prevPayId
from Payroll;
+-------+-----------+
| payId | prevPayId |
+-------+-----------+
| 17 | NULL |
| 18 | 17 |
| 19 | 18 |
| 20 | NULL |
| 21 | 20 |
+-------+-----------+
Related
I could not fiddle this out for hours now.
I would like to have the total price in one sql select.
Given is a json column where the key is the productId and the value is the quantity.
The customer can have multiple order items.
The quantity must be multiplied with net_price and tax_price.
In SUM This gives the total price.
I can do this relational without json, but my preference is a json column.
I prepared an example to make it clear:
Given:
CREATE TABLE order_items (
`customer_id` VARCHAR(26),
`products` json
);
INSERT INTO order_items VALUES ('01G51A4EK52RHB361SMXH2D5KL', '{"01G51A4EK52RHB361SMXH2D5KH": 10, "01G51A4EK52RHB361SMXH2D5KK": 20}');
INSERT INTO order_items VALUES ('01G51A4EK52RHB361SMXH2D5KL', '{"01G51A4EK52RHB361SMXH2D5KH": 30}');
INSERT INTO order_items VALUES ('01G51A4EK52RHB361SMXH2D5KL', '{"01G51A4EK52RHB361SMXH2D5KH": 30}');
CREATE TABLE product (
`productId` VARCHAR(26),
`net_price` INTEGER,
`tax_price` INTEGER
);
INSERT INTO product VALUES ('01G51A4EK52RHB361SMXH2D5KH', 100, 20);
INSERT INTO product VALUES ('01G51A4EK52RHB361SMXH2D5KK', 200, 10);
What I have by now but it is incomplete:
SELECT
JSON_UNQUOTE(
JSON_EXTRACT(
JSON_KEYS(`products`),
CONCAT(
'$[',
ROW_NUMBER() OVER(PARTITION BY `products`) -1,
']'
)
)
) AS "productId",quantity
FROM order_items
JOIN JSON_TABLE(
products,
'$.*' COLUMNS (
quantity VARCHAR(50) PATH '$'
)
) j
WHERE `order_items`.`customer_id` = '01G51A4EK52RHB361SMXH2D5KL';
DB-Fiddle:
https://www.db-fiddle.com/f/reewoqUCQxeDLJb6zpb1RG/1
Could someone help me out here? Is this even possible?
Thank you!
Here's a solution to get the corresponding net_price and tax_price. I am not sure how you want to use them.
SELECT j.productId,
JSON_UNQUOTE(JSON_EXTRACT(i.products, CONCAT('$."', j.productId, '"'))) AS quantity,
p.net_price,
p.tax_price
FROM order_items AS i
CROSS JOIN JSON_TABLE(JSON_KEYS(i.products),
'$[*]' COLUMNS (
productId VARCHAR(26) PATH '$'
)
) AS j
JOIN product AS p USING (productId)
WHERE i.`customer_id` = '01G51A4EK52RHB361SMXH2D5KL';
Output given your sample data:
+----------------------------+----------+-----------+-----------+
| productId | quantity | net_price | tax_price |
+----------------------------+----------+-----------+-----------+
| 01G51A4EK52RHB361SMXH2D5KH | 30 | 100 | 20 |
| 01G51A4EK52RHB361SMXH2D5KH | 30 | 100 | 20 |
| 01G51A4EK52RHB361SMXH2D5KH | 10 | 100 | 20 |
| 01G51A4EK52RHB361SMXH2D5KK | 20 | 200 | 10 |
+----------------------------+----------+-----------+-----------+
Calculating the total aggregate price:
SELECT SUM(
JSON_UNQUOTE(JSON_EXTRACT(i.products, CONCAT('$."', j.productId, '"')))
* (p.net_price + p.tax_price)
) AS total_price
FROM order_items AS i
CROSS JOIN JSON_TABLE(JSON_KEYS(i.products),
'$[*]' COLUMNS (
productId VARCHAR(26) PATH '$'
)
) AS j
JOIN product AS p USING (productId)
WHERE i.`customer_id` = '01G51A4EK52RHB361SMXH2D5KL';
Output:
+-------------+
| total_price |
+-------------+
| 12600 |
+-------------+
I have a schema that has following two tables
1. People -
+-------+----------------+------------+-----------------+-----------------+
| ID | NAME | DOJ | PREV_COMPANY_ID | CURR_COMPANY_ID |
+-------+----------------+------------+-----------------+-----------------+
| 1795f | ALEX BROWN | 1973-03-02 | 4e5b | 123a |
| 8772 | Chris Mitchell | 2016-06-15 | 4746 | 4e5b |
| 5e03 | Patt Hobbs | 1976-09-14 | 4e5b | 123b |
+-------+----------------+------------+-----------------+-----------------+
2. Company -
+-------+---------------+
| ID | NAME |
+-------+---------------+
| 4746 | Mora-Sullivan |
| 49de6 | Harmon-Miller |
| 4e5b | Fakesmith |
+-------+---------------+
I want to write the query to find the following -
First Determine the Company/Companies that has highest no.of employees & then display it's employees with previous company.
I have found out the company which has the highest employees using sql query. i.e Fakesmith here.
SELECT PREV_COMPANY_ID, COUNT(*) as count
FROM PEOPLE
GROUP BY PREV_COMPANY_ID
ORDER BY count DESC;
But I am unable to buildup any logic to find, the current employers of the highest number of employees with their previous company names. How can I solve this query?
Are you trying something like this:
create table people(
id varchar(9) not null ,
name varchar(50) not null ,
doj date ,
PREV_COMPANY_ID varchar(50),
CURR_COMPANY_ID varchar(50),
Primary key id(`id`)
);
insert into people values ('1795f','ALEX BROWN','1973-03-02','4e5b','123a'),('8772','Chris Mitchell','2016-06-15','4746','4e5b'),('5e03','Patt Hobbs','1976-09-14','4e5b','123b');
create table company(
id varchar(9) not null ,
name varchar(50) not null ,
Primary key id(`id`)
);
insert into company values ('4746','Mora-Sullivan'),('49de6','Harmon-Miller'),('4e5b','Fakesmith');
select p.name,p.CURR_COMPANY_ID,company.name as company_name
from people p join (select PREV_COMPANY_ID ,count(*) as comp_high_nr from people group by PREV_COMPANY_ID order by comp_high_nr desc limit 1) as t on p.CURR_COMPANY_ID =t.PREV_COMPANY_ID join company on p.PREV_COMPANY_ID=company.id ;
Try this one will help you
CREATE TABLE tblcompany (
id varchar(9) NOT NULL,
name varchar(50) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
INSERT INTO tblcompany (id,name) VALUES
('1','Mora-Sullivan'),
('2','Harmon-Miller'),
('3','Fakesmith');
CREATE TABLE tblpeople (
id varchar(9) NOT NULL,
name varchar(50) NOT NULL,
doj date DEFAULT NULL,
PREV_COMPANY_ID varchar(50) DEFAULT NULL,
CURR_COMPANY_ID varchar(50) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
INSERT INTO tblpeople (id,name,doj,PREV_COMPANY_ID,CURR_COMPANY_ID) VALUES
('1','ALEX BROWN','1973-03-02','1','2'),
('2','Chris Mitchell','2016-06-15','1','3'),
('3','Patt Hobbs','1976-09-14','2','3');
First, we need to get companies with the highest employee's
SELECT t1.CURR_COMPANY_ID, COUNT(t1.id) as `NoOfEmployee` FROM tblpeople as t1 GROUP BY t1.CURR_COMPANY_ID ORDER BY NoOfEmployee DESC LIMIT 1;
Then we join with people table to get all employees for that company
SELECT t1.*, t2.name as `CURR_COMPANY`, t3.name as `PREV_COMPANY` FROM tblpeople as t1 LEFT JOIN tblcompany as t2 ON t1.CURR_COMPANY_ID=t2.id LEFT JOIN tblcompany as t3 ON t1.PREV_COMPANY_ID=t3.id INNER JOIN (SELECT CURR_COMPANY_ID, COUNT(id) as EmployeeCount FROM tblpeople GROUP BY CURR_COMPANY_ID ORDER BY EmployeeCount DESC LIMIT 1) as t4 ON t1.CURR_COMPANY_ID=t4.CURR_COMPANY_ID;
Please check if following query serve your purpose
SELECT *
FROM PEOPLE
WHERE CURR_COMPANY_ID IN ( SELECT PREV_COMPANY_ID
FROM ( SELECT PREV_COMPANY_ID, COUNT (1) AS C
FROM PEOPLE
GROUP BY CURR_COMPANY_ID
ORDER BY C DESC)
ORDER BY c DESC)
So, I have two data and they did't have any relationship
first Table
tglAmbil Satuan Harga
11-08-2017 1 10000
11-08-2017 2 10000
15-08-2017 2 10000
01-09-2017 2 10000
Second Table
tglAmbil Satuan Harga
21-08-2017 1 10000
And I try to make my SELECT result look like this:
Month(tglAmbil) date_format(tglAmbil,"$m") Harga
8 Agustus 60000
9 September 20000
using this query:
SELECT
MONTH(`tglAmbil`),
DATE_FORMAT(tglAmbil,"%M"),
SUM(detaillpjunbudged.satuan * detaillpjunbudged.harga) +
IFNULL(prokers.total,0)
FROM `unbudged` LEFT JOIN lpjunbudged ON unbudged.kdUnbudgeding =
lpjunbudged.kdUnbudgeding
LEFT JOIN detaillpjunbudged ON lpjunbudged.kdLpjUnbudged =
detaillpjunbudged.kdLpjUnbudged,
(SELECT MONTH(`tglAmbil`) AS
tgl,DATE_FORMAT(tglAmbil,"%M"),SUM(detaillpjproker.satuan *
detaillpjproker.harga) AS total,`kdDetailProker` FROM `realisasiproker` LEFT
JOIN lpjproker ON realisasiproker.kdRealisasiProker =
lpjproker.kdRealisasiProker LEFT JOIN detaillpjproker ON lpjproker.kdLPJ =
detaillpjproker.kdLPJ GROUP BY MONTH(tglAmbil)) AS prokers
WHERE MONTH(`tglAmbil`) = prokers.tgl GROUP BY MONTH(`tglAmbil`)
but the result that I got is:
Month(tglAmbil) date_format(tglAmbil,"$m") Harga
8 Agustus 60000
so, what the real cause? I confused with this sytax problem. Thank you
Consider the following:
DROP TABLE IF EXISTS table1;
CREATE TABLE table1
(purchase_date DATE NOT NULL
,quantity INT NOT NULL
,price INT NOT NULL
);
INSERT INTO table1 VALUES
('2017-08-11',1,10000),
('2017-08-11',2,10000),
('2017-08-15',2,10000),
('2017-09-01',2,10000);
DROP TABLE IF EXISTS table2;
CREATE TABLE table2
(purchase_date DATE NOT NULL
,quantity INT NOT NULL
,price INT NOT NULL
);
INSERT INTO table2 VALUES
('2017-08-21',1,10000);
SELECT DATE_FORMAT(purchase_date,'%Y-%m') yearmonth
, SUM(quantity*price) total
FROM
(
SELECT * FROM table1
UNION
SELECT * FROM table2
) x
GROUP
BY yearmonth;
+-----------+-------+
| yearmonth | total |
+-----------+-------+
| 2017-08 | 60000 |
| 2017-09 | 20000 |
+-----------+-------+
I want to create a query in MySQL, on an order table and verify if it has a booking id, if it does not have a booking_id it should available on all relations in the invoice table.
I want the value returned to be a boolean in a single field.
Taken the example given, in
Case of id #1 I expect an immediate true, because it's available
Case of id #2 I expect an "delayed" false from the invoice table as not all related invoices have an booking_id, it should only return true if invoice id #3 actually has an booking id, meaning all invoices have an booking_id when the order does not.
I've tried several ways but still failed and don't even know what the best way to tackle this is.
Thanks for your input in advance!
Table order:
|----+------------+
| id | booking_id |
|----+------------+
| 1 | 123 |
| 2 | NULL |
|----+------------+
Table invoice:
+----+----------+------------+
| id | order_id | booking_id |
+----+----------+------------+
| 1 | 1 | 123 |
| 2 | 2 | 124 |
| 3 | 2 | NULL |
+----+----------+------------+
Schema
CREATE TABLE IF NOT EXISTS `invoice` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` int(11) NOT NULL,
`booking_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE IF NOT EXISTS `order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`booking_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
If I understand you correctly, this is the base query for your request:
SELECT
O.id
, SUM(CASE WHEN I.booking_id IS NOT NULL THEN 1 ELSE 0 END) AS booked_count
, COUNT(1) AS total_count
, CASE WHEN SUM(CASE WHEN I.booking_id IS NOT NULL THEN 1 ELSE 0 END) = COUNT(1) THEN 1 ELSE 0 END AS has_all_bookings
FROM
`order` O
LEFT JOIN invoice I
ON O.id = I.order_id
GROUP BY
O.id
If you want to check if there is no record in the invoice table add the COUNT(1) to the last CASE statement as an additional condition (COUNT(1) = 0)
Fiddle Demo
I have not understood how the logic works out when the order is booked but some of the invoices are not. I'll presume either is good for a true value (OR logic). I'd avoid COUNT and GROUP BY and go for a SUBSELECT, which works fine in MySQL (I'm using and old 5.1.73-1 version).
This query gives you both values in distinct columns:
SELECT o.*
, (booking_id IS NOT NULL) AS order_booked
, (NOT EXISTS (SELECT id FROM `invoice` WHERE order_id=o.id AND booking_id IS NULL)) AS invoices_all_booked
FROM `order` o
Of course you can combine the values:
SELECT o.*
, (booking_id IS NOT NULL OR NOT EXISTS (SELECT id FROM `invoice` WHERE order_id=o.id AND booking_id IS NULL)) AS booked
FROM `order` o
Here you go, create a view that does it
create view booked_view as
select `order`.id as order_id
,
case when booking_id > 0 then true
when exists (SELECT id FROM invoice WHERE order_id=`order`.id AND invoice.booking_id IS NULL) then true
else false
end as booked
from `order` ;
Then just join your view to the order table and you will have your boolean column 'booked'
select o.id, booked from `order` o
join booked_view on (o.id = booked_view.order_id)
I have two tables with data
CREATE TABLE `MASTER` (
`NAME` VARCHAR(10) NOT NULL,
`QTY` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`NAME`)
);
NAME | QTY
----------
'ABC' | 0
'XYZ' | 0
CREATE TABLE `DETAIL` (
`NAME` VARCHAR(10) NOT NULL,
`QTY` INT(10) UNSIGNED NOT NULL,
`FLAG` TINYINT(1) UNSIGNED NOT NULL
);
NAME | QTY| FLAG
--------------------
'ABC' | 10 | 0
'ABC' | 20 | 0
'PQR' | 15 | 0
'PQR' | 25 | 0
i want to update sum(detail.qty) to master and set its flag to 1
so i have written query
UPDATE MASTER M, DETAIL D
SET M.QTY = M.QTY + D.QTY,
D.FLAG =1
WHERE M.NAME = D.NAME;
i have guesed MASTER.QTY should be 30 (10 + 20) from detail table.
but it only updates the first value
actual value is MASTER.QTY =10 (only updtaed first value from table)
How can i get MASTER.QTY =30?
Try this query:
update `MASTER` m,`DETAIL` d,
(
SELECT `NAME`, SUM( `QTY` ) as `QTY`
FROM `DETAIL`
GROUP BY `NAME`
) s
SET m.QTY = s.QTY,
d.FLAG = 1
WHERE
m.NAME = s.NAME
AND m.NAME = d.NAME
;
SQLFiddle demo --> http://www.sqlfiddle.com/#!2/ab355/1
IMO, your Master table is unnecessary. You don't need it if the amount of rows ain't in a > 5-digit range.
This equals the MASTER table:
SELECT NAME, SUM(QTY), FLAG FROM DETAIL GROUP BY NAME;
You can create a view from that easily.
Your answer anyways:
UPDATE MASTER m
JOIN DETAIL d ON m.NAME = d.NAME
SET
d.FLAG = 1,
m.QTY = (SELECT SUM(QTY) FROM DETAIL WHERE NAME = d.NAME GROUP BY NAME)
WHERE m.NAME = d.NAME
Also, always follow normalization rules: https://en.wikipedia.org/wiki/Database_normalization