How can I select a row from another table based on the sum of column from the left table
SELECT Group_concat(c.cartid SEPARATOR ',') AS CartIDs,
Sum(c.grandtotal) AS Sum,
r.percentage
FROM carts c
LEFT JOIN rebates r
ON Sum(c.grandtotal) >= r.fromamountpurchased
AND Sum(c.grandtotal) <= r.toamountpurchased
WHERE c.ispaid = '1'
AND c.addedtorebates = '0'
GROUP BY c.customerid
But this doesn't work. I also tried HAVING also doesn't work.
Is it possible in one query?
Thanks!
UPDATE:
CREATE TABLE IF NOT EXISTS `carts` (
`CartID` bigint(20) NOT NULL AUTO_INCREMENT,
`CustomerID` bigint(20) NOT NULL,
`GrandTotal` decimal(10,2) NOT NULL,
`IsPaid` enum('0','1','2') NOT NULL,
`AddedToRebates` enum('0','1') NOT NULL,
PRIMARY KEY (`CartID`)
)
INSERT INTO `carts` (`CartID`, `CustomerID`, `GrandTotal`, `IsPaid`,
`AddedToRebates`, ) VALUES
(71, 28, '57450.00', '1', '0' ),
(73, 28, '57450.00', '1', '0');
CREATE TABLE IF NOT EXISTS `rebates` (
`RebateID` bigint(20) NOT NULL AUTO_INCREMENT,
`Percentage` varchar(255) NOT NULL COMMENT 'in %',
`FromAmountPurchased` decimal(10,2) NOT NULL,
`ToAmountPurchased` decimal(10,2) NOT NULL,
`CashEquivalent` decimal(10,2) NOT NULL,
PRIMARY KEY (`RebateID`)
)
INSERT INTO `rebates` (`RebateID`, `Percentage`, `FromAmountPurchased`,
`ToAmountPurchased`, `CashEquivalent`) VALUES
(1, '5', '50000.00', '69999.00', '3000.00'),
(2, '10', '70000.00', '79999.00', '5000.00'),
(3, '15', '80000.00', '89999.00', '6000.00'),
(4, '20', '90000.00', '99999.00', '7000.00'),
(5, '25', '100000.00', '150000.00', '8000.00'),
(6, '0', '0.00', '49999.00', '0.00');
Try this:
select q1.CartIDs, q1.total, r.percentage
from
(select group_concat(c.cartid) as CartIDs, sum(c.grandtotal) as total
from carts c
where c.ispaid = '1'
and c.addedtorebates = '0'
group by c.customerid ) q1
left join rebates r
on q1.total >= r.fromamountpurchased
and q1.total <= r.toamountpurchased
Here is a demo fiddle for you: http://sqlfiddle.com/#!9/d27f5/3
You cannot use aggregate functions like SUM() in the join predicate, so in this instance, a subquery is useful
You can achieve your result with a sub query. Please note that this sub query requires an additional scan of carts.
SELECT GROUP_CONCAT(c.CartID SEPARATOR ',') AS CartIDs, SUM(c.GrandTotal) as Sum, r.Percentage
FROM carts c
INNER JOIN (
SELECT SUM(GrandTotal) as grandTotal, CustomerID
FROM carts
GROUP BY CustomerID
) cSums ON cSums.CustomerID = c.CustomerID
LEFT JOIN rebates r ON cSums.grandTotal >= r.FromAmountPurchased AND cSums.grandTotal <= r.ToAmountPurchased
WHERE c.IsPaid = '1' AND c.AddedToRebates = '0' GROUP BY c.CustomerID
Related
I have student and event tables linked by sid.
CREATE TABLE `students` (
`sid` int(8) NOT NULL COMMENT 'use',
`active` enum('Yes','No','vac','Grad') NOT NULL DEFAULT 'Yes',
`name` varchar(130) DEFAULT NULL,
`bus` varchar(130) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `students` (`sid`, `LEFT(name, 2)`, `bus`) VALUES
(51, 'Me', 'BusA'),
(52, 'Hi', 'BusA'),
(59, 'An', 'BusA'),
(70, 'Mi', 'BusB'),
(100, 'Yu', 'BusB');
CREATE TABLE `STATevent` (
`eventid` int(24) NOT NULL,
`sid` int(4) NOT NULL,
`date` datetime NOT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`level` enum('absent','bus') CHARACTER SET utf8 NOT NULL,
`color` varchar(10) NOT NULL,
`Percent` tinyint(5) NOT NULL,
`note` varchar(266) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `STATevent` (`eventid`, `sid`, `date`, `created`, `level`, `color`, `Percent`, `note`) VALUES
(43, 59, '2022-11-30 21:17:04', '2022-11-28 12:17:04', 'bus', 'red', 100, '');
The student can select not to get bus service, which shows as an entry (like eventid 43 above). I can get the list of 'bus students', along with an id to show who cancelled service and who hasn't.
SELECT C.name, C.sid, O.sid AS 'bid', C.bus FROM students C
LEFT JOIN STATevent O ON C.sid = O.sid
WHERE C.bus LIKE 'Bus%' AND C.active = 'Yes' ;
However, when I try to limit where with the date, the result shows only the one who cancelled service.
SELECT C.name, C.sid, O.sid AS 'bid', C.bus FROM students C
LEFT JOIN STATevent O ON C.sid = O.sid
WHERE C.bus LIKE 'Bus%' AND C.active = 'Yes' AND O.date LIKE '2022-11-29%';
How can I add this limiter and get the full results like the first query?
Thanks in advance for your help.
You may move the restriction on the event date to the ON clause of the left join:
SELECT c.name, c.sid, o.sid AS bid, c.bus
FROM students c
LEFT JOIN STATevent o
ON o.sid = c.sid AND
DATE(o.date) = '2022-11-29'
WHERE c.bus LIKE 'Bus%' AND c.active = 'Yes';
For students who did not cancel service, the bid would be reported as null.
You want to show all students that use a bus servvice, but exclude those that opt out for a certain date. You can use NOT EXISTS or NOT IN to do this lookup.
SELECT *
FROM `students`
WHERE bus LIKE 'Bus%' AND active = 'Yes'
AND sid NOT IN
(
SELECT sid
FROM `STATevent`
WHERE DATE(date) = DATE '2022-11-30'
)
ORDER BY sid;
If you want to show all potential bus service users instead with a flag whether they attend that day or not, you can move the condition to the select clause:
SELECT s.*
sid IN
(
SELECT sid
FROM `STATevent`
WHERE DATE(date) = DATE '2022-11-30'
) AS opt_out
FROM `students` s
WHERE bus LIKE 'Bus%' AND active = 'Yes'
ORDER BY sid;
Demo: https://dbfiddle.uk/TxyzF564
I have two tables project_payment and payment_schedule
CREATE TABLE project_payment (
`tenant_id` INTEGER,
`project_id` INTEGER,
`payment_date` datetime NOT NULL,
PRIMARY KEY(tenant_id,project_id,payment_date)
);
INSERT INTO project_payment
(`tenant_id`, `project_id`, `payment_date`)
VALUES
('1', '1', '2020-12-11 07:09:16'),
('1', '1', '2020-12-15 07:09:16');
CREATE TABLE payment_schedule (
`tenant_id` INTEGER not null ,
`project_id` INTEGER not null,
`schedule_date` datetime NOT NULL,
PRIMARY KEY(tenant_id,project_id,schedule_date)
);
INSERT INTO payment_schedule
(`tenant_id`, `project_id`, `schedule_date`)
VALUES
('1', '1', '2020-12-15 07:09:16'),
('1', '1', '2020-12-28 07:09:29'),
('1', '1', '2021-01-02 01:00:00');
Here I take last_payment_date, now i need to get the next payment schedule date
SELECT MAX(pp.payment_date) last_payment_date
FROM project_payment pp
JOIN payment_schedule ps
ON ps.tenant_id = pp.tenant_id
AND ps.project_id = pp.project_id;
I don't knw how to select the next date so I didn't write that code here..
I need to get next payment date from the schedule_date according to the current date(present day)
Expected output:
last_payment_date next_schedule_date
2020-12-15 07:09:16 2020-12-28 07:09:29
SELECT p.payment_date last_payment_date,
s.schedule_date next_schedule_date
FROM ( SELECT MAX(payment_date) payment_date
FROM project_payment ) p
JOIN payment_schedule s ON p.payment_date < s.schedule_date
ORDER BY s.schedule_date LIMIT 1
In the query below I am "JOINING" another table where i.isPrimary > 0 and if all i.isPrimary are 0 I just get the first result.
The result set from the query is as expected, but I want to bring more values from each subselect.
I am getting the error: SQL Error (1241): Operand should contain 1 column(s).
How can this query be rewritten in order to get more results from each subselect?
Thanks
-- borrowed from https://stackoverflow.com/q/7745609/808921
CREATE TABLE IF NOT EXISTS `ResearchEntity` (
`id` int(6) unsigned NOT NULL,
`name` varchar(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `ResearchEntity` (`id`, `name`) VALUES
('1', 'one'),
('2', 'two'),
('3', 'three');
CREATE TABLE IF NOT EXISTS `ProfileImageEntity` (
`id` int(6) unsigned NOT NULL,
`isPrimary` int(1) unsigned NOT NULL,
`value` varchar(200) NOT NULL,
`researchId` int(2) unsigned NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `ProfileImageEntity` (`id`,`isPrimary`, `value`,`researchId`) VALUES
('1', 0, 'not primary',1),
('2', 0, 'not primary',1),
('3', 1, 'primary!!!',1),
('4', 0, 'primary!!!',2),
('5', 0, 'not primary',2),
('6', 0, 'not primary',2)
;
CREATE TABLE IF NOT EXISTS `UserNameEntity` (
`id` int(6) unsigned NOT NULL,
`isPrimary` int(1) unsigned NOT NULL,
`value` varchar(200) NOT NULL,
`researchId` int(2) unsigned NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `UserNameEntity` (`id`,`isPrimary`, `value`,`researchId`) VALUES
('1', 0, 'first one, should be returned',1),
('2', 0, 'not primary',1),
('3', 0, 'primary',1),
('4', 1, 'primary',3),
('5', 0, 'not primary',3),
('6', 0, 'not primary',3);
SQL FIDDLE
: http://sqlfiddle.com/#!9/028218/1
SELECT r.*,
(SELECT i.id FROM ProfileImageEntity i WHERE i.researchId = r.id ORDER BY i.isPrimary DESC, i.id ASC LIMIT 1 ) AS primaryImageId,
(SELECT i.id FROM UserNameEntity i WHERE i.researchId = r.id ORDER BY i.isPrimary DESC, i.id ASC LIMIT 1 ) AS primaryImageId
FROM ResearchEntity r
ORDER BY id DESC;
What I understood from your question and comment that you want more columns from sub Query which is not possible. So try this query:
It is easy in MySql 8 but you are using MySql 5.7 where it a little bit tricky So try this:
select
t1.*,
t2.id AS primaryImageId,
t2.value AS primaryImageValue,
t3.id AS primaryUserId,
t3.value AS primaryUserValue
from ResearchEntity t1
left join (
SELECT *,
IF(researchId=#last,#_seq:=#_seq+1,#_seq:=1) AS rn,
#last:=researchId
FROM ProfileImageEntity , (SELECT #_seq:=1, #last:=0) r
ORDER BY researchId,isPrimary DESC, id ASC
) t2 on t1.id=t2.researchId and t2.rn=1
left join (
SELECT *,
IF(researchId=#last,#_seq:=#_seq+1,#_seq:=1) AS rn,
#last:=researchId
FROM UserNameEntity , (SELECT #_seq:=1, #last:=0) r
ORDER BY researchId,isPrimary DESC, id ASC
) t3 on t1.id=t3.researchId and t3.rn=1
order by t1.id
DEMO
In MySql 8 using row_number()
with cte as (
SELECT *,
row_number() over (partition by researchId ORDER BY isPrimary DESC, id ASC) rn
FROM ProfileImageEntity
),
cte1 as (
sELECT *,
row_number() over (partition by researchId ORDER BY isPrimary DESC, id ASC) rn
FROM UserNameEntity
)
select
t1.*,
t2.id AS primaryImageId,
t2.value AS primaryImageValue,
t3.id AS primaryUserId,
t3.value AS primaryUserValue
from ResearchEntity t1 left join cte t2 on t1.id=t2.researchId and t2.rn=1
left join cte1 t3 on t1.id=t3.researchId and t3.rn=1
try left join
SELECT r.*,i.id FROM ResearchEntity r left join ProfileImageEntity i on r.id = i.researchId
ORDER BY i.isPrimary,i.id DESC;
you just need to left join 2 times
SELECT r.*,i.id,j.id FROM ResearchEntity r left join ProfileImageEntity i on r.id = i.researchId left join UserNameEntity j on r.id=j.researchId ORDER BY i.isPrimary,i.id DESC;
It's about get sum product's quantity and name from joined orders grouped by date
I have two tables:
CREATE TABLE IF NOT EXISTS `orderproduct` (
`id` int(5) UNSIGNED NOT NULL AUTO_INCREMENT,
`quantity` int(3) NOT NULL,
`name` varchar(100) NOT NULL,
`fk_orders_id` int(3) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
INSERT INTO `orderproduct` (`id`, `quantity`, `name`, `fk_orders_id`) VALUES
(1, 3, 'Boulgour de bléss', 1),
(2, 2, 'Casarecce d\'épeautre', 1),
(3, 1, 'Cerneaux de noix', 1),
(5, 2, 'Boulgour de bléss', 3),
(6, 2, 'Casarecce d\'épeautre', 3),
(7, 4, 'Casarecce d\'épeautre', 4),
(8, 4, 'Cerneaux de noix', 4);
INSERT INTO `orders` (`id`, `date`) VALUES
(1, '2020-06-29 17:02:11'),
(3, '2020-06-29 10:56:47'),
(4, '2020-06-30 11:20:24');
DROP TABLE IF EXISTS `orders`;
CREATE TABLE IF NOT EXISTS `orders` (
`id` int(3) NOT NULL AUTO_INCREMENT,
`date` timestamp NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
the exemple with the order grouped by date and make a sum from his same product quantity:
order 29/6
productsA quantity=1
productsB quantity=2
productsC quantity=3
order 29/6
productsA quantity=4
order 30/6
productsA quantity=1
productsB quantity=2
My knowledge of mysql is to basic here wath i have tried for the moment:
SELECT o.date, p.name, sum(p.quantity)
FROM `orders` o , `orderproduct` p
WHERE p.fk_orders_id = o.id
GROUP BY p.name
The sum of quantities are grouped by product but dont know how take care of grouping by orders date.
I tried also some sub query
(i know this not working because sub Q; return more than 1 row and shoul be used witn 'IN' but it is just for illustrate the idéé):
select o.date,p.name, (
SELECT sum(p.quantity)
FROM `orderproduct` p
GROUP BY p.name
)
FROM `orders` o , `orderproduct` p
WHERE p.fk_orders_id = o.id
Desired result could be:
order.date productname product.sumQuantity (name field)
2020-06-29 'Boulgour de bléss' 5, 'Casarecce d'épeautre' 4, 'Cerneaux de noix' 1
2020-06-30 'Casarecce d'épeautre' 4, 'Cerneaux de noix' 4,
thanks to #MdRanaHossain for the solution
SELECT date(o.date) date, p.name, sum(p.quantity)
from orderproduct p, orders o
where o.id = p.fk_orders_id
GROUP by date(o.date), p.name
This question already has answers here:
Join tables with SUM issue in MYSQL
(2 answers)
Closed 5 years ago.
I am on Mysql version 5.5. I have two tables - product, ordr.
CREATE TABLE `product` (
`id` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `ordr` (
`id` int(11) NOT NULL,
`product_id` varchar(45) DEFAULT NULL,
`status` varchar(45) DEFAULT NULL,
`qty` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Here is how they are populated -
insert into product values (20, 'pen');
insert into ordr values (100, 20, 'queue', 5);
insert into ordr values (110, 20, 'queue', 5);
insert into ordr values (120, 20, 'pending', 10);
insert into ordr values (130, 20, 'pending', 10);
insert into ordr values (140, 20, 'pending', 10);
I want to get the total quantity of products that are in two different statuses. For the test data above data, I want to see 10 for queue quantity and 30 for pending quantity.
When I run
select p.name, sum(o.qty) as queue_qty, sum(o2.qty) as pending_qty
from product p
left outer join ordr o on o.product_id = p.id and o.status = 'queue'
left outer join ordr o2 on o2.product_id = p.id and o2.status = 'pending'
where p.id = 20;
I get
name - pen
queue_qty - 30
pending_qty - 60
Can someone help me fix this SQL?
You need to aggregate the information before it's joined. Since you have two 1-n relationships, your join logic is duplicating information.
select
p.name
, o.qty as qty_queue
, o2.qty as qty_pending
from
product p
join (
select
product_id
, sum(qty) as qty
from
ordr
where
ordr.status = 'queue'
group by
product_id
) o
on p.id = o.product_id
join (
select
product_id
, sum(qty) as qty
from
ordr
where
ordr.status = 'pending'
group by
product_id
) o2
on p.id = o2.product_id
group by
p.name