Mysql selecting rows - mysql

I have a database scheme with a table like this:
id --- username --- sex
1 A 1
2 D 2
3 F 1
4 G 2
5 H 1
6 x 1
7 r 1
I want to select only 2 males and lets say 4 females, male is 1 and female is 2. How would we achieve that in one mysql query and if I have more var's to select by ?

(select * from your_table where sex = 1 limit 2)
union all
(select * from your_table where sex = 2 limit 4)

Related

sql or python solution for getting merging duplicate rows into one in an ordered table and reordering them

Can someone help me do this in SQL in a select statement?
I have a table xyz as follow:
ColumnID
Column A
Column B
1
1
A
1
2
B
1
3
C
1
4
D
2
1
A
2
2
B
2
3
C
2
4
C
3
1
A
3
2
A
3
3
B
3
4
B
4
1
A
4
2
B
4
3
V
4
4
V
I want it to change to this:
Column A
Column B
1
A
2
B
3
C
4
D
1
A
2
B
3
C
1
A
2
B
1
A
2
B
3
V
haven't tried anything
Here is the solution for anyone who has the same question:
with abc as (select columnID, ROW_NUMBER() over (PARTITION by columnID, column_b ORDER BY columnID) as column_a, column_b
from xyz)
select row_number() over (partition by columnID order by column_a asc) as column_a, column_b
from abc where row_num = 1

subtract from values by groups

What is the best way to subtract the lowest value from all values by group?
Something like:
ID Name Value
1 A 10
1 B 40
1 C 100
2 A 20
2 B 80
2 C 90
3 A 4
3 B 7
3 C 8
turn to:
ID Name Value
1 A 0
1 B 30
1 C 90
2 A 0
2 B 60
2 C 70
3 A 0
3 B 3
3 C 4
Use window functions:
select id, name, value - min(value) over (partition by id) as
from t;
If you actually want to update the values, in MySQL, aggregation and join are probably the simplest solution:
update t join
(select id, min(value) as min_value
from t
group by id
) tt
on t.id = tt.id
set value = value - min_value
where min_value <> 0;

MySQL Query 2 records at top followed by the rest

I'm stuck with the following problem.
I have a website with for example supermarket shopping items. People can search the website for items.
Now I want on the search result page at the top 2 items to be displayed that I have selected to be on offer. There can be lots more items on offer.
So for example, someone would search for shampoo, the query would display all the shampoo items in the database table but I want just 2 shampoo offer items at the top of the query. There could be 2 or more shampoo offers in the database table, then the other would just not be shown.
Example with names :
Table:
id name C D
----------------------------------
1 Jack 1 1
2 Joe 1 1
3 Dave 3 0
4 Sue 1 0
5 Mike 1 1
6 Steve 4 0
7 David 1 0
8 Susan 4 1
9 Marc 1 1
10 Ronald 4 1
11 Michael 4 1
EXAMPLE 1
Query :
WHERE C = 1 AND D = 1 (But only maximum of 2 'D' records, these 2 'D' records show at the top of the result)
Desired Query Result :
id name C D
----------------------------------
1 Jack 1 1
2 Joe 1 1
4 Sue 1 0
7 David 1 0
EXAMPLE 2
Query :
WHERE C = 4 AND D = 1 (But only maximum of 2 'D' records, these 2 'D' records show at the top of the result)
Desired Query Result :
id name C D
----------------------------------
8 Susan 4 1
10 Ronald 4 1
6 Steve 4 0
I hope this explains my goal what I'm trying to achieve.
Many thanks for any help or suggestions!
That's two queries that you can combine with UNION ALL:
select * from mytable where c = 1 and d = 1 limit 2
union all
select * from mytable where c = 1 and d = 0
order by d desc;
UPDATE: If you want to have the two rows chosen randomly, then order by RAND(). (Without an ORDER BY the rows are chosen arbitrarily, which means it's not guaranteed to get the same two rows picked again when re-running the query &dash; but it's quite likely.) As we need an ORDER BY for a partial query (the first query in the complete union-alled query), we must use parentheses, because otherwise only one ORDER BY would be allowed, namely for the complete query at the query's end.
(select * from mytable where c = 1 and d = 1 order by rand() limit 2)
union all
(select * from mytable where c = 1 and d = 0)
order by d desc;
SQL fiddle: http://sqlfiddle.com/#!9/ed53f6/3.

MySql subqueries and max or group by?

I have this table:
ID STUDENT CLASS QUESTION ANSWER TIME
1 1 1 1 c 12:30
2 1 1 1 d 12:36
3 1 1 2 a 12:38
4 2 1 1 b 11:24
5 2 1 1 c 11:26
6 2 1 3 d 11:35
7 2 3 3 b 11:24
I'm trying to write a query that does this:
For each STUDENT in a specific CLASS select the most recent ANSWER for each QUESTION.
So, choosing class "1" would return:
ID STUDENT CLASS QUESTION ANSWER TIME
2 1 1 1 d 12:36
3 1 1 2 a 12:38
5 2 1 1 c 11:26
6 2 1 3 d 11:35
I've tried various combinations of subqueries, joins, and grouping, but nothing is working. Any ideas?
You can use a sub-query to get most recent ANSWER per QUESTION, Then use this as a derived table and join back to the original table:
SELECT m.*
FROM mytable AS m
INNER JOIN (
SELECT STUDENT, QUESTION, MAX(`TIME`) AS mTime
FROM mytable
WHERE CLASS = 1
GROUP BY STUDENT, QUESTION
) AS d ON m.STUDENT = d.STUDENT AND m.QUESTION = d.QUESTION AND m.`TIME` = d.mTime
WHERE m.CLASS = 1
Demo here

how to retrieve hierarchical data retrieved as a collection

I have implemented the following hierarchical data using MySQL
1
|----- 2
|----- 3
4
|----- 5
|----- 6
|----- 7
id | path | level | parent_id | content |
-------------------------------------------------------------------
1 1 1 NULL xxx
2 1:2 2 1 yyy
3 1:3 2 1 abc
4 4 1 NULL zzz
5 4:5 2 4 yyy
6 4:6 2 4 abc
7 4:6:7 3 6 abc
Assuming I have only these records,
how do I retrieve them in a tree structure and yet within a single collection starting with the last tree?
What I expected from the query or stored procedure is to return me the following in exactly this order
id
-----
4
5
6
7
1
2
3
How do I do the same but starting with the first tree?
id
-----
1
2
3
4
5
6
7
try including order by desc
ORDER by path desc,id asc
To cope with parents / children possibly something like this:-
SELECT PathTable.*, SUM(OrderVal) AS OrderCalc
FROM
(
SELECT id,
POW(100, MaxDepth-i-1) * SUBSTRING_INDEX(SUBSTRING_INDEX(path, ':', (i+1)), ':', -1) AS OrderVal
FROM PathTable
CROSS JOIN (SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) Sub1
CROSS JOIN (SELECT MAX(LENGTH(path) - LENGTH(REPLACE(path, ':', ''))) + 1 AS MaxDepth FROM PathTable) Sub2
WHERE i <= (LENGTH(path) - LENGTH(REPLACE(path, ':', '')))
) Sub1
INNER JOIN PathTable
ON Sub1.id = PathTable.id
GROUP BY PathTable.id
ORDER BY OrderCalc
This is splitting up the path field and calculating an order value based on 100 to the power of the level of the bit of path, taking into account the max number of bits of path, times that bit of path (so 4:6:7 lands up as 7 + 6 * 100^1 + 4 * 100^2), then ordering by that.
100 chosen just as it is bigger than the largest single value in the path.