select previous row based on group in MYSQL - mysql

I have this data.
create table #temp_student_ticket
(
student_ticket_id int identity(1,1) primary key,
student_id int ,
ticket_amount numeric(9,2)
)
insert into #temp_student_ticket
(
student_id,
ticket_amount
)
values
(
1,30.00
),(2,180.00),(1,75.00),(2,66.00)
select * from #temp_student_ticket
I need to select the previous row for the same student. Output should look like below.
student_id student_ticket_id amount prev_student_ticket_id prev_amount
1 1 20.00 NULL NULL
1 3 75.00 1 20.00
1 5 30.00 3 75.00
2 2 180.00 NULL NULL
2 4 66.00 2 180.00
What is the most optimized way to select this format on 50 million rows of table in MYSQL.
Thanks in advance.

Try this:
SELECT tst1.student_id, tst1.student_ticket_id, tst1.ticket_amount,
tst2.student_ticket_id prev_student_ticket_id, tst2.ticket_amount previous_amount
FROM temp_student_ticket tst1
LEFT JOIN temp_student_ticket tst2
ON (tst1.student_id = tst2.student_id
AND tst1.student_ticket_id > tst2.student_ticket_id
AND tst2.student_ticket_id = (SELECT MAX(tst3.student_ticket_id)
FROM temp_student_ticket tst3
WHERE tst3.student_id = tst1.student_id
AND tst3.student_ticket_id < tst1.student_ticket_id));

Related

Return count of how many occurrences there are

I have a MySQL table that looks like this:
user_id
other_id
date
123456789
123
date1
213454678
123
date2
Here, user_id is a multikey and is re-occurring for some entries. Date is irrelevant for this task.
I tried this query:
select user_id, count(user_id) as count from exp_pixel_data group by user_id;
And this returned
user_id
count
123324345456456576587
7
453545435343455343453
3
777676766776675654454
2
345565664545665654645
1
This result tells me how often a user_id is occurring in the table. This may be a good start, but now i need how often this counts are occurring in the result of the last query. So the question is, how many user_ids occur 7 times in the table?
I need a SQL query which returns something like this:
count
times_ocurring
1
123
2
100
3
2
and so on.
This means that 123 times there are user_ids that occur one time in the main table, 100 times user_ids that occur 2 Times and 2 times user_ids that occur 3 times.
Is it possible you're trying to do this (count the counts)?
Fiddle
SELECT COUNT(xcount) AS count_of_counts
, xcount
FROM (SELECT user_id
, COUNT(user_id) AS xcount
FROM exp_pixel_data
GROUP BY user_id
) xxx
GROUP BY xcount
ORDER BY COUNT(xcount)
;
and with MySQL, we can use the derived column name in the ORDER BY:
SELECT COUNT(xcount) AS count_of_counts
, xcount
FROM (SELECT user_id
, COUNT(user_id) AS xcount
FROM exp_pixel_data
GROUP BY user_id
) xxx
GROUP BY xcount
ORDER BY count_of_counts
;
Result (given test data below):
+-----------------+--------+
| count_of_counts | xcount |
+-----------------+--------+
| 1 | 5 |
| 2 | 2 |
| 2 | 1 |
+-----------------+--------+
Setup:
CREATE TABLE exp_pixel_data (user_id int, val int default 0);
INSERT INTO exp_pixel_data (user_id) VALUES
(12345)
, (12345)
, (12399)
, (12399)
, (12388)
, (12377)
, (12355)
, (12355)
, (12355)
, (12355)
, (12355)
;

How to SELECT based on value of another SELECT for the same month value

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 |
+-----------+-------+

How to perform complex calculation and update to a view in MySQL?

I want to calculate how many Car_A and Car_B can be built with my existing items in warehouse?
Expecting to see the Car_A and Car_B with maximum number that I can build in the view below.
Please let me know if table design is bad or else.
What I have done: What I use everyday is export to Excel and calculate in Excel manually.
First I would suggest you to split the car and tool in the warehouse.
You can just create another column and put some sign for it like C = Car and T = Tools
Or you can create another table and put your car in it I prefer this way and my answer will goes this way and this is mydata test
CREATE TABLE [dbo].[Assembly](
[id_item] [int] NULL,
[name] [varchar](100) NULL,
[quantity] [int] NULL
)
insert into [Assembly]
select 1,'Car_A',0
union all
select 2,'Car_B',0
CREATE TABLE [dbo].[Warehouse](
[id_item] [int] NULL,
[name] [varchar](100) NULL,
[quantity] [numeric](18, 2) NULL
)
insert into [Warehouse]
select 1,'Door',30
union all
select 2,'Wheel',30
union all
select 3,'Light',30
CREATE TABLE [dbo].[Relation](
[assembly_id] [int] NULL,
[required_item] [int] NULL,
[required_quantity] [int] NULL
)
insert into [relation]
select 1,1,10
union all
select 1,2,10
union all
select 1,3,10
union all
select 2,1,3
union all
select 2,2,3
union all
select 2,3,3
testing the relation
select * from Assembly as a
inner join Relation as r on r.assembly_id = a.id_item
inner join Warehouse as w on w.id_item = r.required_item
The result is
id_item name quantity assembly_id required_item required_quantity id_item name quantity
1 Car_A 0 1 1 10 1 Door 30.00
1 Car_A 0 1 2 10 2 Wheel 30.00
1 Car_A 0 1 3 10 3 Light 30.00
2 Car_B 0 2 1 3 1 Door 30.00
2 Car_B 0 2 2 3 2 Wheel 30.00
2 Car_B 0 2 3 3 3 Light 30.00
and here your solution
select a.name,min(a.new_quantity) as new_quantity
from (
select a.name,floor(w.quantity/r.required_quantity) as new_quantity
from Assembly as a
inner join Relation as r on r.assembly_id = a.id_item
inner join Warehouse as w on w.id_item = r.required_item
) as a
group by a.name
name new_quantity
Car_A 3
Car_B 10
you can try editing your tools left to see if it's correct or not. Hope this help:)

How can you select unique values with MySQL GROUP BY

I have a table full of messages between users, and I want to select the last message from each user where the userFrom is not my user(4), however if the last message to another user(userTo) is the last message between my user(4) and another user then that should be the value for that msg in the return records.
TABLE messages
id|userFrom|userTo|msg
-------------------------
1 | 4 | 9 |msg 1
2 | 9 | 4 |msg 2
3 | 4 | 63 |msg 1
4 | 63 | 4 |msg 2
5 | 4 | 9 |msg 3
6 | 9 | 4 |msg 4
7 | 9 | 4 |msg 5
8 | 63 | 4 |msg 3
My end goal is to use the data to show a list of messages from unique users where each row is a different user and it shows the last message between my user and that user(for visual reference i'm trying to create something like Facebook messages)
How i would like the above table data returned
id|userFrom|msg
-------------------------
7 | 9 |msg 5
8 | 63 |msg 3
i need the userFrom to be unique so i can extend the query to do additional joins to get the actual varchar username from the users table where the userFrom is some user but not my own user.
Here's one option with least and greatest:
select id, userfrom, userto, msg
from messages m join (
select max(id) maxid
from messages
group by least(userfrom, userto), greatest(userfrom, userto)
) t on m.id = t.maxid
SQL Fiddle Demo
BTW -- I assume your expected results are incorrect. You don't have id = 8 in your sample data.
Try this one:
SELECT messages.id, messages.userFrom, messages.msg
FROM messages INNER JOIN
(SELECT userFrom, max(id) AS mxid
FROM messages
GROUP BY userFrom) sub
ON messages.id = sub.mxid
WHERE messages.UserFrom <> 4
I think this is what you are looking for
CREATE TABLE [dbo].[UserMessage](
[id] [int] NOT NULL,
[userFrom] [int] NOT NULL,
[userTo] [int] NOT NULL,
[msg] [varchar](50) NOT NULL
) ON [PRIMARY]
insert into UserMessage values(1,4,9,'msg 1')
insert into UserMessage values(2,9,4,'msg 2')
insert into UserMessage values(3,4,63,'msg 1')
insert into UserMessage values(4,63,4,'msg 2')
insert into UserMessage values(5,4,9,'msg 3')
insert into UserMessage values(6,9,4,'msg 4')
insert into UserMessage values(7,9,4,'msg 5')
insert into UserMessage values(8,63,4,'msg 3')
SELECT lastMesageFrom.*, um.msg
FROM
(
select max(id) as id,UserFrom from UserMessage
where UserTo = 4
Group by UserFrom
)as lastMesageFrom
Left Outer join UserMessage um on um.id = lastMesageFrom.id
EDIT: Verified with MySQL: http://sqlfiddle.com/#!9/1045b/1
You must read the difference between where and having clause.
First, filter your records by WHERE clause (where userFrom!=4)
Then use the group by
And finally filter the messages that were sent to you by HAVING clause (having userTo=4)

MySQL Max with wrong fields

When executing below query
SELECT `game_turns`.`in_darts`, `game_turns`.`date`, MAX(game_turns.score) AS max_score
FROM `game_turns`
JOIN `games` ON `games`.`id` = `game_turns`.`game_id` AND `games`.`training` = 1
WHERE `game_turns`.`uid` = 2
AND `game_turns`.`out` = 1
AND `game_turns`.`in_darts` = 3
ORDER BY `game_turns`.`score` DESC
LIMIT 1
I get the max score for that user id (uid) and out in 3 darts, but the rest (date) is wrong.
Fields are
Score Uid GameID Score out in_darts date
121 2 4 8 1 3 2015-07-21 13:52:12
8465 2 142 100 1 3 2015-09-05 19:46:29
It returns the score 100 from row ID 8465 but the rest is from row ID 121
I have googled it and came on some Stackoverflow results saying that I should use ORDER BY and LIMIT 1, but looks like it aint working for me.
Order by Date also didn't do the trick.
A simple order by and limit should do what you want:
SELECT gt.`in_darts`, gt.`date`, gt.score
FROM `game_turns` gt JOIN
`games` g
ON g.`id` = gt.`game_id` AND g.`training` = 1
WHERE gt.`uid` = 2 AND gt.`out` = 1 AND gt.`in_darts` = 3
ORDER BY gt.`score` DESC
LIMIT 1;
There is no need for aggregation.
If seeking a solution that would work for multiple UID's then aggregation becomes useful - via a subquery.
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE Table1
(`Score_A` int, `Uid` int, `GameID` int, `Score_B` int, `out` int, `in_darts` int, `date` datetime)
;
INSERT INTO Table1
(`Score_A`, `Uid`, `GameID`, `Score_B`, `out`, `in_darts`, `date`)
VALUES
(121, 2, 4, 8, 1, 3, '2015-07-21 13:52:12'),
(8465, 2, 142, 100, 1, 3, '2015-09-05 19:46:29')
;
Query 1:
SELECT
t.*
FROM table1 t
INNER JOIN (
SELECT Uid, max(Score_B) as Score_B
FROM table1
GROUP BY uid
) msb ON t.Uid = msb.Uid and t.Score_B = msb.Score_B
Results:
| Score_A | Uid | GameID | Score_B | out | in_darts | date |
|---------|-----|--------|---------|-----|----------|-----------------------------|
| 8465 | 2 | 142 | 100 | 1 | 3 | September, 05 2015 19:46:29 |