I have the issue using MAX() and GROUP BY.
I have next tables:
personal_prizes
___________ ___________ _________ __________
| id | userId | specId| group |
|___________|___________|_________|__________|
| 1 | 1 | 1 | 1 |
|___________|___________|_________|__________|
| 2 | 1 | 2 | 1 |
|___________|___________|_________|__________|
| 3 | 2 | 3 | 1 |
|___________|___________|_________|__________|
| 4 | 2 | 4 | 2 |
|___________|___________|_________|__________|
| 5 | 1 | 5 | 2 |
|___________|___________|_________|__________|
| 6 | 1 | 6 | 2 |
|___________|___________|_________|__________|
| 7 | 2 | 7 | 3 |
|___________|___________|_________|__________|
prizes
___________ ___________ _________
| id | title | group |
|___________|___________|_________|
| 1 | First | 1 |
|___________|___________|_________|
| 2 | Second | 1 |
|___________|___________|_________|
| 3 | Newby | 1 |
|___________|___________|_________|
| 4 | General| 2 |
|___________|___________|_________|
| 5 | Leter | 2 |
|___________|___________|_________|
| 6 | Ter | 2 |
|___________|___________|_________|
| 7 | Mentor | 3 |
|___________|___________|_________|
So, I need to select highest title for user.
E.g. user with id = 1 must have prizes 'Second', 'Ter'.
I don't know how to implement it in one query(((
So, first of all, I try to select highest specID for user.
I try next:
SELECT pp.specID
FROM personal_prizes pp
WHERE pp.specID IN (SELECT MAX(pp1.id)
FROM personal_prizes pp1
WHERE pp1.userId = 1
GROUP BY pp1.group)
And it doesnt work.
So please help me to solve this problem.
And if you help to select prizes for user it will be great!
The problem I perceive here is that prizes.id isn't really a reliable way to determine which is the "highest" prize. Ignoring this however I suggest using ROW_NUMBER() OVER() to locate the "highest" prize per user as follows:
Refer to this SQL Fiddle
CREATE TABLE personal_prizes
([id] int, [userId] int, [specId] int, [group] int)
;
INSERT INTO personal_prizes
([id], [userId], [specId], [group])
VALUES
(1, 1, 1, 1),
(2, 1, 2, 1),
(3, 2, 3, 1),
(4, 2, 4, 2),
(5, 1, 5, 2),
(6, 1, 6, 2),
(7, 2, 7, 3)
;
CREATE TABLE prizes
([id] int, [title] varchar(7), [group] int)
;
INSERT INTO prizes
([id], [title], [group])
VALUES
(1, 'First', 1),
(2, 'Second', 1),
(3, 'Newby', 1),
(4, 'General', 2),
(5, 'Leter', 2),
(6, 'Ter', 2),
(7, 'Mentor', 3)
;
Query 1:
select
*
from (
select
pp.*, p.title
, row_number() over(partition by pp.userId order by p.id ASC) as prize_order
from personal_prizes pp
inner join prizes p on pp.specid = p.id
) d
where prize_order = 1
Results:
| id | userId | specId | group | title | prize_order |
|----|--------|--------|-------|-------|-------------|
| 1 | 1 | 1 | 1 | First | 1 |
| 3 | 2 | 3 | 1 | Newby | 1 |
The result can be "reversed" by changing the ORDER BY within the over clause:
select
*
from (
select
pp.*, p.title
, row_number() over(partition by pp.userId order by p.id DESC) as prize_order
from personal_prizes pp
inner join prizes p on pp.specid = p.id
) d
where prize_order = 1
| id | userId | specId | group | title | prize_order |
|----|--------|--------|-------|--------|-------------|
| 6 | 1 | 6 | 2 | Ter | 1 |
| 7 | 2 | 7 | 3 | Mentor | 1 |
You could expand on this logic to locate "highest prize per group" too
select
*
from (
select
pp.*, p.title
, row_number() over(partition by pp.userId, p.[group] order by p.id ASC) as prize_order
from personal_prizes pp
inner join prizes p on pp.specid = p.id
) d
where prize_order = 1
| id | userId | specId | group | title | prize_order |
|----|--------|--------|-------|---------|-------------|
| 1 | 1 | 1 | 1 | First | 1 |
| 5 | 1 | 5 | 2 | Leter | 1 |
| 3 | 2 | 3 | 1 | Newby | 1 |
| 4 | 2 | 4 | 2 | General | 1 |
| 7 | 2 | 7 | 3 | Mentor | 1 |
Related
This is what I have:
Table: parent
| id | name |
| -- | ---- |
| 1 | foo |
| 2 | bar |
| 3 | baz |
Table: child
| id | parent_id | type_id |
| -- | --------- | ------- |
| 1 | 2 | 2 |
| 2 | 2 | 2 |
| 3 | NULL | 2 |
| 4 | 1 | 1 |
| 5 | NULL | 2 |
| 6 | NULL | 1 |
| 7 | 1 | 2 |
| 8 | 3 | 1 |
I want to select all the parent records, together with the number of child having type 2 for each parent record:
| id | name | type_2_count |
| -- | ---- | ------------ |
| 1 | foo | 1 |
| 2 | bar | 2 |
| 3 | baz | 0 |
I tried this:
SELECT p.id, name, COUNT(c.id) type_2_count
FROM parent p LEFT JOIN child c ON c.parent_id = p.id
WHERE c.type_id = 2
GROUP BY p.id;
| id | name | type_2_count |
| -- | ---- | ------------ |
| 2 | bar | 2 |
| 1 | foo | 1 |
But it's missing the third record.
And this:
SELECT p.id, name, t.cnt type_2_count
FROM parent p LEFT JOIN (
SELECT parent_id, COUNT(*) as cnt
FROM child
WHERE type_id = 2
GROUP BY parent_id
) t ON t.parent_id = p.id;
| id | name | type_2_count |
| -- | ---- | ------------ |
| 1 | foo | 1 |
| 2 | bar | 2 |
| 3 | baz | NULL |
But type_2_count is NULL instead of 0 for the third record.
This is the schema I used:
CREATE TABLE IF NOT EXISTS parent (
id INT AUTO_INCREMENT,
name VARCHAR(45) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB;
INSERT INTO parent VALUES (1, 'foo'), (2, 'bar'), (3, 'baz');
CREATE TABLE IF NOT EXISTS child (
id INT AUTO_INCREMENT,
parent_id INT REFERENCES parent(id),
type_id TINYINT NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB;
INSERT INTO child VALUES (1, 2, 2), (2, 2, 2), (3, NULL, 2), (4, 1, 1), (5, NULL, 2), (6, NULL, 1), (7, 1, 2), (8, 3, 1);
In your 1st query the only change you need is to move the condition from the WHERE clause to the ON clause:
SELECT p.id, name, COUNT(c.id) type_2_count
FROM parent p LEFT JOIN child c
ON c.parent_id = p.id AND c.type_id = 2
GROUP BY p.id;
and in your 2nd query use COALESCE() to turn NULL to 0:
SELECT p.id, name,
COALESCE(t.cnt, 0) type_2_count
FROM parent p LEFT JOIN (
SELECT parent_id, COUNT(*) as cnt
FROM child
WHERE type_id = 2
GROUP BY parent_id
) t ON t.parent_id = p.id;
See the demo.
I am trying to use partition by & row_number() to count consecutive duplicate values for a given date range.Essentially its attempting to capture "streaks" If there is a break in the streak the count should start over when the value occurs again.
To reproduce these results here is the code:
CREATE TABLE partion_test (
daily DATE,
response_short_name VARCHAR(10)
);
INSERT INTO `partion_test` (`daily`, `response_short_name`) VALUES
('2020-09-21', 'A'),
('2020-09-25', 'A'),
('2020-09-26', 'A'),
('2020-09-27', 'A'),
('2020-09-28', 'A'),
('2020-09-22', 'B'),
('2020-09-20', 'C'),
('2020-09-23', 'C'),
('2020-09-24', 'C');
SELECT
daily,
response_short_name
,row_number() over (partition by response_short_name order by daily) as seqnum
FROM (
select
daily,
response_short_name
FROM partion_test
order by daily limit 1000
) A;
HERE IS THE CURRENT OUTPUT
| daily | response_short_name | seqnum | |
+------------+---------------------+--------+--+
| 2020-09-21 | A | 1 | |
| 2020-09-25 | A | 2 | |
| 2020-09-26 | A | 3 | |
| 2020-09-27 | A | 4 | |
| 2020-09-28 | A | 5 | |
| 2020-09-22 | B | 1 | |
| 2020-09-20 | C | 1 | |
| 2020-09-23 | C | 2 | |
| 2020-09-24 | C | 3 | |
+------------+---------------------+--------+--+
HERE IS THE DESIRED OUTPOUT
+------------+---------------------+--------+--+
| daily | response_short_name | seqnum | |
+------------+---------------------+--------+--+
| 2020-09-20 | C | 1 | |
| 2020-09-21 | A | 1 | |
| 2020-09-22 | B | 1 | |
| 2020-09-23 | C | 1 | |
| 2020-09-24 | C | 2 | |
| 2020-09-25 | A | 1 | |
| 2020-09-26 | A | 2 | |
| 2020-09-27 | A | 3 | |
| 2020-09-28 | A | 4 | |
+------------+---------------------+--------+--+
Ive been scratching at my brain for a while on this. Any help would be appreciated
You can do:
select *,
row_number() over(partition by grp order by daily) as seqnum
from (
select *,
sum(inc) over(order by daily) as grp
from (
select *,
case when lag(response_short_name) over(order by daily) = response_short_name
then 0 else 1 end as inc
from partion_test
order by daily
) x
) y
order by daily
Result:
daily response_short_name inc grp seqnum
----------- -------------------- ---- ---- ------
2020-09-20 C 1 1 1
2020-09-21 A 1 2 1
2020-09-22 B 1 3 1
2020-09-23 C 1 4 1
2020-09-24 C 0 4 2
2020-09-25 A 1 5 1
2020-09-26 A 0 5 2
2020-09-27 A 0 5 3
2020-09-28 A 0 5 4
See running example at DB Fiddle:
Your data doesn't fit your result, so it is quite diffcult t achieve your result
CREATE TABLE partion_test (
daily DATE,
response_short_name VARCHAR(10)
);
INSERT INTO `partion_test` (`daily`, `response_short_name`) VALUES
('2020-09-21', 'A'),
('2020-09-25', 'A'),
('2020-09-26', 'A'),
('2020-09-27', 'A'),
('2020-09-28', 'A'),
('2020-09-22', 'B'),
('2020-09-20', 'C'),
('2020-09-23', 'C'),
('2020-09-24', 'C');
select `daily`,`response_short_name`,
row_number() over (partition by `response_short_name`, grp order by `daily`) as row_num
from (select t.*,
(row_number() over (order by `daily`) -
row_number() over (partition by `response_short_name` order by `daily`)
) as grp
from partion_test t
) t
ORDER BY `daily`
daily | response_short_name | row_num
:--------- | :------------------ | ------:
2020-09-20 | C | 1
2020-09-21 | A | 1
2020-09-22 | B | 1
2020-09-23 | C | 1
2020-09-24 | C | 2
2020-09-25 | A | 1
2020-09-26 | A | 2
2020-09-27 | A | 3
2020-09-28 | A | 4
db<>fiddle here
I have a table states_risk:
id | state | municipally | rating
example:
id | state | municipally | rating
1 AG AG1 5
2 AG AG2 6
3 AG AG3 2
4 AG AG4 1
5 AG OTHER -
6 AB AB1 0.2
7 AB AB2 2
8 AB AB3 10
9 AB OTHER -
I need to update the value "rating" for municipally = OTHER set the MAX(rating) value by state "AG" - "AB", example: the id 5 set a 6 value from because is the max value for state AG.
You can do it by joining the table to a query that returns the max rating for each state:
update states_risk s inner join (
select state, max(rating) rating
from states_risk
group by state
) g on g.state = s.state
set s.rating = g.rating
where s.municipally = 'OTHER';
See the demo.
Results:
| id | state | municipally | rating |
| --- | ----- | ----------- | ------ |
| 1 | AG | AG1 | 5 |
| 2 | AG | AG2 | 6 |
| 3 | AG | AG3 | 2 |
| 4 | AG | AG4 | 1 |
| 5 | AG | OTHER | 6 |
| 6 | AB | AB1 | 0.2 |
| 7 | AB | AB2 | 2 |
| 8 | AB | AB3 | 10 |
| 9 | AB | OTHER | 10 |
This gives you the max values
SELECT state, max(rating) as maxrating
FROM states_risk
GROUP BY state
This gives you the ones you want to update
SELECT id, state
FROM states_risk
WHERE municiplally = 'OTHER'
So the update is
UPDATE states_risk
SET rating = (
SELECT max(rating) as maxrating
FROM states_risk inner
WHERE inner.state = states_risk.state
)
WHERE municiplally = 'OTHER'
If You column rating has '-' in his Column.
you need also to cast the column
Like
select version();
| version() |
| :-------- |
| 8.0.18 |
CREATE TABLE states_risk
(`id` int, `state` varchar(2), `municipally` varchar(5), `rating` varchar(3))
;
INSERT INTO states_risk
(`id`, `state`, `municipally`, `rating`)
VALUES
(1, 'AG', 'AG1', '5'),
(2, 'AG', 'AG2', '6'),
(3, 'AG', 'AG3', '2'),
(4, 'AG', 'AG4', '1'),
(5, 'AG', 'OTHER', '-'),
(6, 'AB', 'AB1', '0.2'),
(7, 'AB', 'AB2', '2'),
(8, 'AB', 'AB3', '10'),
(9, 'AB', 'OTHER', '-')
;
✓
✓
Select * From states_risk;
id | state | municipally | rating
-: | :---- | :---------- | :-----
1 | AG | AG1 | 5
2 | AG | AG2 | 6
3 | AG | AG3 | 2
4 | AG | AG4 | 1
5 | AG | OTHER | -
6 | AB | AB1 | 0.2
7 | AB | AB2 | 2
8 | AB | AB3 | 10
9 | AB | OTHER | -
SELECT state, MAX(CAST(rating as FLOAT)) MAXrating
FROM states_risk WHERE rating <> '-' GROUP BY state
state | MAXrating
:---- | --------:
AG | 6
AB | 10
UPDATE states_risk sr INNER JOIN (SELECT state, MAX(CAST(rating as FLOAT)) MAXrating
FROM states_risk WHERE rating <> '-' GROUP BY state) t1
ON sr.state = t1.state
SET sr.rating = t1.MAXrating WHERE sr.municipally = 'OTHER';
✓
Select * From states_risk;
id | state | municipally | rating
-: | :---- | :---------- | :-----
1 | AG | AG1 | 5
2 | AG | AG2 | 6
3 | AG | AG3 | 2
4 | AG | AG4 | 1
5 | AG | OTHER | 6
6 | AB | AB1 | 0.2
7 | AB | AB2 | 2
8 | AB | AB3 | 10
9 | AB | OTHER | 10
db<>fiddle here
I have the following tables structure and trying to make a report from these:
___BillableDatas
|--------|------------|---------|--------------|------------|
| BIL_Id | BIL_Date |BIL_Rate | BIL_Quantity | BIL_Status |
|--------|------------|---------|--------------|------------|
| 1 | 2018-03-01 | 105 | 1 | charged |
| 2 | 2018-03-02 | 105 | 1 | cancelled |
| 3 | 2018-03-01 | 15 | 2 | notcharged |
| 4 | 2018-03-01 | 21 | 1 | notcharged |
| 5 | 2018-03-02 | 15 | 2 | notcharged |
| 6 | 2018-03-02 | 21 | 1 | notcharged |
|--------|------------|---------|--------------|------------|
___SalesTaxes
|--------|--------------|------------|
| STX_Id | STX_TaxeName | STX_Amount |
|--------|--------------|------------|
| 8 | Tax 1 | 5.000 |
| 9 | Tax 2 | 5.000 |
| 10 | Tax 3 | 19.975 |
|--------|--------------|------------|
STX_Amount is a percentage.
___ApplicableTaxes
|-----------|-----------|
| ATX_BILId | ATX_STXId |
|-----------|-----------|
| 1 | 8 |
| 1 | 9 |
| 1 | 10 |
| 2 | 8 |
| 2 | 9 |
| 2 | 10 |
| 3 | 9 |
| 3 | 10 |
| 4 | 9 |
| 5 | 9 |
| 5 | 10 |
| 6 | 9 |
|-----------|-----------|
ATX_BILId is the item ID link with ___BillableDatas.
ATX_STXId is the tax ID link with ___SalesTaxes.
I need to get to sum of the items per day
- without tax
- with tax
So mething like this:
|------------------|---------------|------------|
| BIL_RateNonTaxed | BIL_RateTaxed | BIL_Status |
|------------------|---------------|------------|
| 105.00 | 136.47 | charged | <- Taxes #8, #9 and #10 applicable
| 102.00 | 118.035 | notcharged | <- Taxes #9 and #10 applicable
|------------------|---------------|------------|
Explications on the totals:
105 = 105*1 -- (total of the charged item multiply by the quantity)
102 = (15*2)*2+(21*2) -- (total of the notcharged items multiply by the quantity)
136.47 = 105+(105*(5+5+19.975)/100)
119.085 = 102+(((15*2)*2)*(5+19.975)/100+(21*2)*5/100)
My last try was this one:
SELECT
BIL_Date,
(BIL_Rate*BIL_Quantity) AS BIL_RateNonTaxed,
(((BIL_Rate*BIL_Quantity)*SUM(STX_Amount)/100)+BIL_Rate*BIL_Quantity) AS BIL_RateTaxed,
BIL_Status
FROM ___BillableDatas
LEFT JOIN ___SalesTaxes
ON FIND_IN_SET(STX_Id, BIL_ApplicableTaxes) > 0
LEFT JOIN ___ApplicableTaxes
ON ___BillableDatas.BIL_Id = ___ApplicableTaxes.ATX_BILId
WHERE BIL_BookingId=1
GROUP BY BIL_Id AND BIL_Status
ORDER BY BIL_Date
ASC
Please see this SQLFiddle to help you if needed:
http://sqlfiddle.com/#!9/425854f
Thanks.
I cannot bear to work with your naming policy, so I made my own...
DROP TABLE IF EXISTS bills;
CREATE TABLE bills
(bill_id SERIAL PRIMARY KEY
,bill_date DATE NOT NULL
,bill_rate INT NOT NULL
,bill_quantity INT NOT NULL
,bill_status ENUM('charged','cancelled','notcharged')
);
INSERT INTO bills VALUES
(1,'2018-03-01',105,1,'charged'),
(2,'2018-03-02',105,1,'cancelled'),
(3,'2018-03-01',15,2,'notcharged'),
(4,'2018-03-01',21,1,'notcharged'),
(5,'2018-03-02',15,2,'notcharged'),
(6,'2018-03-02',21,1,'notcharged');
DROP TABLE IF EXISTS sales_taxes;
CREATE TABLE sales_taxes
(sales_tax_id SERIAL PRIMARY KEY
,sales_tax_name VARCHAR(12) NOT NULL
,sales_tax_amount DECIMAL(5,3) NOT NULL
);
INSERT INTO sales_taxes VALUES
( 8,'Tax 1', 5.000),
( 9,'Tax 2', 5.000),
(10,'Tax 3',19.975);
DROP TABLE IF EXISTS applicable_taxes;
CREATE TABLE applicable_taxes
(bill_id INT NOT NULL
,sales_tax_id INT NOT NULL
,PRIMARY KEY(bill_id,sales_tax_id)
);
INSERT INTO applicable_taxes VALUES
(1, 8),
(1, 9),
(1,10),
(2, 8),
(2, 9),
(2,10),
(3, 9),
(3,10),
(4, 9),
(5, 9),
(5,10),
(6, 9);
SELECT bill_status
, SUM(bill_rate*bill_quantity) nontaxed
, SUM((bill_rate*bill_quantity)+(bill_rate*bill_quantity*total_sales_tax/100)) taxed
FROM
( SELECT b.*
, SUM(t.sales_tax_amount) total_sales_tax
FROM bills b
JOIN applicable_taxes bt
ON bt.bill_id = b.bill_id
JOIN sales_taxes t
ON t.sales_tax_id = bt.sales_tax_id
GROUP
BY bill_id
) x
GROUP
BY bill_status;
+-------------+---------+-------------+
| bill_status | untaxed | total |
+-------------+---------+-------------+
| charged | 105 | 136.4737500 |
| cancelled | 105 | 136.4737500 |
| notcharged | 102 | 119.0850000 |
+-------------+---------+-------------+
My answer is very slightly different from yours, so one of us has made a mistake somewhere. Either way, this should get you pretty close.
SELECT a.BIL_Date, BIL_RateNonTaxed, BIL_RateNonTaxed+BIL_RateTaxed AS BIL_RateTaxed FROM (
SELECT BIL_Date,
SUM(BIL_Rate*BIL_Quantity) AS BIL_RateNonTaxed
FROM ___BillableDatas
WHERE BIL_Status != 'cancelled'
GROUP BY BIL_Date
) a INNER JOIN (
SELECT BIL_Date,
(((BIL_Rate*BIL_Quantity)*SUM(STX_Amount)/100)) AS BIL_RateTaxed
FROM ___BillableDatas
LEFT JOIN ___ApplicableTaxes
ON ___BillableDatas.BIL_Id = ___ApplicableTaxes.ATX_BILId
LEFT JOIN ___SalesTaxes
ON STX_Id = ATX_STXId
WHERE BIL_Status != 'cancelled'
GROUP BY BIL_Date
) b
ON a.BIL_Date = b.BIL_Date
ORDER BY a.BIL_Date;
Explanation:
Your BIL_RateNonTaxed calculation is not using the ___SalesTaxes table, so it must not appear on the query otherwise it would interfere the SUM function.
Howerver, your BIL_RateTaxed does use the ___SalesTaxes table. In that case, I solved by creating 2 subqueries and joining the results.
I know there are better answers, but I'm not familiar with MySQL syntax.
And I want my output like the following:
My requirement is the following:
latest service ID
default = 'Y'
How should I write the query? Can someone help me?
You could use this:
select se.svcid, p1.pname as serviceprovider, p2.pname as tmidprovider
from tmid t
inner join (select sno, max(svcid) as maxsvcid from service group by sno) s
on t.sno = s.sno and t.`default` = 'Y'
inner join service se on se.svcid = s.maxsvcid
left join provider p1 on se.pid = p1.pid
left join provider p2 on t.pid = p2.pid;
Table
create table service (svcid int, sno varchar(20), pid int);
insert into service values
(1, '11-11-11-11', 1), (2, '11-11-11-11', 2), (3, '11-11-11-12', 1), (4, '11-11-11-12', 2), (5, '11-11-11-13', NULL);
create table tmid (id int, sno varchar(20), pid int, `default` char(1));
insert into tmid values
(1, '11-11-11-11', 1, 'N'),(2, '11-11-11-11', 2, 'Y'),(3, '11-11-11-12', 1, 'N'),
(4, '11-11-11-12', 2, 'Y'),(5, '11-11-11-13', 2, 'Y'),(6, '11-11-11-13', 3, 'N');
create table provider (pid int, pname varchar(20));
insert into provider values (1, 'Ambank'), (2, 'Citybank'), (3, 'CIMB Bank');
Data
mysql> select * from service;
+-------+-------------+------+
| svcid | sno | pid |
+-------+-------------+------+
| 1 | 11-11-11-11 | 1 |
| 2 | 11-11-11-11 | 2 |
| 3 | 11-11-11-12 | 1 |
| 4 | 11-11-11-12 | 2 |
| 5 | 11-11-11-13 | NULL |
+-------+-------------+------+
mysql> select * from tmid;
+------+-------------+------+---------+
| id | sno | pid | default |
+------+-------------+------+---------+
| 1 | 11-11-11-11 | 1 | N |
| 2 | 11-11-11-11 | 2 | Y |
| 3 | 11-11-11-12 | 1 | N |
| 4 | 11-11-11-12 | 2 | Y |
| 5 | 11-11-11-13 | 2 | Y |
| 6 | 11-11-11-13 | 3 | N |
+------+-------------+------+---------+
mysql> select * from provider;
+------+-----------+
| pid | pname |
+------+-----------+
| 1 | Ambank |
| 2 | Citybank |
| 3 | CIMB Bank |
+------+-----------+
Result
+-------+-----------------+--------------+
| svcid | serviceprovider | tmidprovider |
+-------+-----------------+--------------+
| 2 | Citybank | Citybank |
| 4 | Citybank | Citybank |
| 5 | NULL | Citybank |
+-------+-----------------+--------------+