I'm sure this sort of question has come up before but I've been searching and can't find anything similar to what I need.
Edit: so after some reading this looks like it falls under pivots and uses group concat. If anybody has any insight id really appreciate it.
I have 3 tables (unnecessary fields & data stripped out for simplicity):
Students
id name
------------------
1 John
2 Jane
Tests
id name
------------------
1 Test1
2 Test2
Results
id test_id student_id result
--------------------------------------
1 1 1 90
2 1 2 70
3 2 1 50
4 2 2 95
What I want is to be able to produce a table like this:
Name Average Test1 Test2
-----------------------------------
John 70 90 50
Jane 92.5 70 95
I know how to get the average, and I'm sure I could do this with an ugly set of loops and php logic but I'd like to get the most efficient solution. Any help is greatly appreciated.
SELECT
s.name,
avg(r.result) AS average,
t1.result AS test1,
t2.result AS test2
FROM
students s,
results r,
results t1,
results t2
WHERE
r.student_id = s.id AND
t1.test_id = 1 AND
t1.student_id = s.id AND
t2.test_id = 2 AND
t2.student_id = s.id
GROUP BY s.id;
+------+---------+-------+-------+
| name | average | test1 | test2 |
+------+---------+-------+-------+
| John | 70 | 90 | 50 |
| Jane | 82.5 | 70 | 95 |
+------+---------+-------+-------+
Edit: You can't really make the test columns dynamically based on the contents of the tests table. You can pick specific values to use as columns though.
You'll want to look at the AVG function.
Try This:
mysql> Select s.Name as Name, avg(r.result) as Average
from result as r join Student as s
on r.id=s.id group by (r.id)
you will have something like this:
Name Average
-----------------
John 70
Jane 92.5
You can't put a row as a column, imagine that John have 100000 times the test1, it will no be possible to put it as column.
Related
I can't really explain it in words because it is hard for me. I'll just show you what I need to accomplish.
So lets say I have 2 tables, admin and records.
admin table with sample data:
a_id | a_name
1 | haime
2 | joseph
Record table with sample data:
r_id | r_amount | r_a_create_by | r_a_update_by
1 | 99 | 1 | 2
So I have a transaction record that is created by admin with ID of 1 and updated by ID of 2. Now how can I make a select query of that? If I want the output of something like :
1 | 99 | haime | joseph
You need to join the admin 2 times. This should work:
select r.r_id, r.r_amount, a.a_name, b.a_name
from records r
join admin a on r.r_a_create_by = a.a_id
join admin b on r.r_a_update_by = b.a_id
I am not very good at sql but I am getting there. I have searched stackoverflow but I can't seem to find the solution and I hope someone out there can help me. I have a table (users) with data like the following. The book_id column is a key to another table that contains a book the user is subscribed to.
|--------|---------------------|------------------|
| id | book_id | name |
|--------|---------------------|------------------|
| 1 | 1 | jim |
| 2 | 1 | joyce |
| 3 | 1 | mike |
| 4 | 1 | eleven |
| 5 | 2 | max |
| 6 | 2 | dustin |
| 7 | 2 | lucas |
|--------|---------------------|------------------|
I have a function in my PHP code that returns two random users from a specific book id (either 1 or 2). Query one returns the result in column 1 and result two returns the results in column 2 like:
|---------------------|------------------|
| 1 | 2 |
|---------------------|------------------|
| jim | max |
| joyce | dustin |
|---------------------|------------------|
I have achieved this by running two separate queries as seen below. I want to know if it's possible to achieve this functionality with one query and how.
$random_users_with_book_id_1 = SELECT name FROM users WHERE book_id=1 LIMIT 2
$random_users_with_book_id_2 = SELECT name FROM users WHERE book_id=2 LIMIT 2
Again, I apologise if it's too specific. The query below has been closest to what I was trying to achieve.:
SELECT a.name AS book_id_1, b.name AS book_id_2
FROM users a, users b
WHERE a.book_id=1 AND b.book_id = 2
LIMIT 2
EDIT: I have created a fiddle to play around with his. I appreciate any help! Thank you!! http://sqlfiddle.com/#!9/7fcbca/1
It is easy actually :)
you can use UNION like this:
SELECT * FROM (
(SELECT * FROM user WHERE n_id=1 LIMIT 2)
UNION
(SELECT * FROM user WHERE n_id=2 LIMIT 2))
collection;
if you read this article about the documentation you can use the () to group the individual queries and the apply the union in the middle. Without the parenthesis it would still LIMIT 2 and show only the two first. Ref. "To apply ORDER BY or LIMIT to an individual SELECT, place the clause inside the parentheses that enclose the SELECT:"
If you want to combine the queries in MySQL, you can just use parentheses:
(SELECT name
FROM users
WHERE n_id = 1
LIMIT 2
) UNION ALL
(SELECT name
FROM users
WHERE n_id = 2
LIMIT 2
);
First, only use UNION if you specifically want to incur the overhead of removing duplicates. Otherwise, use UNION ALL.
Second, this does not return random rows. This returns arbitrary rows. In many cases, this might be two rows near the beginning of the data. If you want random rows, then use ORDER BY rand():
(SELECT name
FROM users
WHERE n_id = 1
ORDER by rand()
LIMIT 2
) UNION ALL
(SELECT name
FROM users
WHERE n_id = 2
ORDER BY rand()
LIMIT 2
);
There are other methods that are more efficient, but this should be fine for up to a few thousand rows.
None of the questions on file seems to be about my precise problem.
Is it possible to sequence detail lines based on the number of detail lines for that order you have in a single query?
Consider the following simplified table:
Order number Article number
------------ --------------
123 1
123 2
123 3
234 1
234 2
345 1
456 1
456 2
456 3
456 4
456 5
The number of detail lines for each order would be
Order number Number of lines
------------ ---------------
123 3
234 2
345 1
456 5
Is it possible to select the order number, article number in descending order by total number of detail lines for each detail line? In other words the desired results are
Order number Article number
------------ --------------
456 1
456 2
456 3
456 4
456 5
123 1
123 2
123 3
234 1
234 2
345 1
I can do it with multiple queries and temporary tables or extra columns. Neither simple SELECTS, SELF JOINs nor UNIONs appear to give me the results I want. Is it possible to do with a single query?
This query should work as it's getting the count from the join and then ordering it by the count.
select t1.orderNumber, t1.articleNumber from myTable t1
inner join
(
select orderNumber, count(articleNumber) as count from myTable
group by orderNumber
) t2
on t1.orderNumber = t2.orderNumber
order by t2.count desc, t1.orderNumber, t1.articleNumber
To better expain it:
We are first selecting all the data, then we are inner joining a table that has the count for each order number, once we have this we can then order it by count DESC so we get the order number with the highest count on top and we can then add additional sorting in the Order By
In the interests of future readers (when MySQL 8.x is production ready and it supports window functions) you can avoid the intermediate subquery and join by using COUNT() OVER(partition by ...) like this:
select t1.orderNumber, t1.articleNumber f
from myTable t1
order by
count(*) over(partition by t1.orderNumber) DESC
, t1.orderNumber
, t1.articleNumber
;
orderNumber | f
----------: | -:
456 | 1
456 | 2
456 | 3
456 | 4
456 | 5
123 | 1
123 | 2
123 | 3
234 | 1
234 | 2
345 | 1
ps: The example above done in MariaDB 10.2 to show MySQL(ish) syntax at work (& it's standards complaint SQL anyway).
dbfiddle here
If I understand the problem correctly, following query should work:
select t1.order_number, t1.Article_number
from t1
inner join (select order_number,count(*) as cnt from t1 group by order_number) as t2
on t1.order_number = t2.order_number
order by t2.cnt desc,t1.order_number,t1.Article_number;
Hope it helps!
I recently got this question on interview which I failed to answer. The question was to list the number of duplicates that appear in a column employer like from this table
id | employer | employee
1 | isro | dude1
2 | isro | dude 2
3 | cnd | dude 3
4 | df | dsfdef
5 | dfdf | dfdfd
...
so the result should be like
isro = 2
df = 4
dfsf = 6
how do i achieve this?
I know there is count(*) which i could use with select statement with where clause, but how do i achieve the above result.
The HAVING clause can be used to filter on aggregated values:
SELECT employer, COUNT(*)
FROM yourTable
GROUP BY employer
HAVING COUNT(*) > 1
assuming TableName is the name of the table you want to select from, this would be your answer.
SELECT employer, count(employer)
FROM TableName
GROUP BY employer
HAVING COUNT(*) > 1
here is an answer to a very similar question that has some more info for you.
How to count occurrences of a column value efficiently in SQL?
I have three tables: Player, Stats and Team.
**Player Table** **Team Table**
----------------- ----------------
id Name Age id Team Ratio
----------------- ----------------
1 Player1 15 1 Team1 10
2 Player2 20 2 Team2 5
3 Player3 40 3 Team3 40
**Stats Table**
-----------------------------
TName Column Value A B
-----------------------------
Player Age Young 10 30
Player Age Mature 30 50
Player Age Old 50 70
Team Ratio Good 20 40
Team Ratio Medium 8 20
Team Ratio Bad 0 8
I have to write fuzzy query with some member function which will show me result who is old in this group:
select function(Player.age, Stats.A, Stats.B) from Player join Stats where TName = 'Player'
Another task is to write query which will show me who has Bad ratio:
select function(Team.ratio, Stats.A, Stats.B) from Team join Stats where TName = 'Team'
The problem is that I need to show this results on one table. I was trying subqueries select (first_query),(second_query) but I got error Subquery returns more than 1 row
EDIT
I didn't paste here my tables but I made simpler version of that. Because of that results may not be valid:
I got:
**function(Player.age, Stats.A, Stats.B)**
------------------------------------------
0.22222
0.44444
1
**function(Team.ratio, Stats.A, Stats.B)**
------------------------------------------
0.52
0.1
0
But I want to have:
|**function(Player...) | function(Team...)**|
| ----------------------------------------|
| 0.22222 | 0.52 |
| 0.44444 | 0.1 |
| 1 | 1 |
maybe this work!
select * from (first_query) , (second_query)
The actual answer was combination of vahid and verhie comments, and this is how it looks like:
select pl,te from
(select function(Player.age, Stats.A, Stats.B), id from Player join Stats where TName = 'Player') as pl
join
(select function(Team.ratio, Stats.A, Stats.B), id from Team join Stats where TName = 'Team') as te
on pl.id = te.id
Thanks for help.