For example, I have 2 table 'meta' and 'log'
in meta table:
| type | score |
|------|-------|
| a | 1 |
| b | 2 |
| c | 3 |
in log table:
| log_id | log_type | object_id |
|--------|----------|-----------|
| 1 | a | 13 |
| 2 | b | 13 |
| 3 | a | 14 |
| 4 | c | 14 |
| 5 | b | 15 |
| 6 | c | 15 |
so we know:
object 13 got score: a+b = 3
object 14 got score: a+c = 4
object 15 got score: b+c = 5
I want to query log table group by object id and order by sum of object score, is it possible?
select log.object_id, sum(meta.score)
from log
left join meta on meta.type = log.log_type
group by log.object_id
order by sum(meta.score) desc
This will produced the desired output
SELECT object_id, sum(score) from log
INNER JOIN meta on meta.type = log.log_type group by object_id ORDER BY sum(score);
But have you got the correct table design? You need to join on the meta.type and log.log_type column but this implies that if the log_type is 'a' the value of 3 is common for all object_ids is this really what you want?
Try this
Select object_id,sum(score) as c FROM `log` as a INNER JOIN `meta` as b on a.log_type=b.type group by object_id order by c desc
SELECT log.object_id, sum(score) total_score
FROM meta
INNER JOIN log on meta.type = log.log_type
GROUP BY log.object_id
Related
I have database table like
transactions
-----------
id
code
date
amount
formalities
-----------
id
transaction_id
this is query to get max value of transactions
SELECT MAX(transaction_id) FROM `transactions` n LEFT JOIN `formalities` r ON r.transaction_id = n.id
But what I want to achieve here is to get the max value of id group by transactions code, but the value must check if the transactions have relation to formalities or not.
If yes, get max value where they relate.
If not just get the usual max value.
Is there a query to achieve something like this?
example:
transactions
--------------------
id | code | amount |
1 | ABC | 10000 |
2 | ABC | 20000 |
3 | KOO | 10000 |
4 | ABC | 20000 |
5 | KOO | 30000 |
6 | KOO | 10000 |
formalities
-----------
id | transaction_id |
1 | 3 |
2 | 5 |
The result I want is getting the following output from the transactions table
id
--
4
5 ( priority the one that have relation and get the max value)
Use a LEFT JOIN and get both - MAX(transactions.id) and MAX(formalities.transaction_id):
select t.code, max(f.transaction_id), max(t.id)
from transactions t
left join formalities f on f.transaction_id = t.id
group by t.code
The result would be
| code | max(f.transaction_id) | max(t.id) |
| ---- | --------------------- | --------- |
| ABC | NULL | 4 |
| KOO | 5 | 6 |
View on DB Fiddle
To "prioritize" transaction_id column from formalities table you can use COALESCE(), which will return the first non NULL value:
select t.code, coalesce(max(f.transaction_id), max(t.id)) as max_transaction_id
from transactions t
left join formalities f on f.transaction_id = t.id
group by t.code
Result:
| code | max_transaction_id |
| ---- | ------------------ |
| ABC | 4 |
| KOO | 5 |
View on DB Fiddle
I am not sure if I am getting the question right, but why don't you simply use -
SELECT MAX(transaction_id) FROM `transactions` n INNER JOIN `formalities` r ON r.transaction_id = n.id group by n.code
Table:
person | borrow_date | is_borrowed | SN | date | id
1 | 2019-01-10...| 1 | 20 |2019-01-10...| 6
3 | 2019-01-09...| 3 | 10 |2019-01-09...| 5
1 | 2019-01-08...| 1 | 10 |2019-01-08...| 4
2 | 2019-01-08...| 1 | 10 |2019-01-08...| 3
1 | NULL | 2 | 20 |2019-01-07...| 2
1 | NULL | 2 | 10 |2019-01-07...| 1
My wanted output is to select newest rows where "is_borrowed" equals 1 and grouped by SN, so that when the query is executed with person=2 or person=3 then it would retrieve empty set. Whereas for person=1 it would give back two rows.
Wanted output (where person=1):
person | borrow_date | is_borrowed | SN | date |id
1 | 2019-01-10...| 1 | 20 | 2019-01-10...|6
1 | 2019-01-08...| 1 | 10 | 2019-01-08...|4
Wanted output (where person=2):
EMPTY SET
Wanted output (where person=3):
EMPTY SET
This is my current query and it sadly doesn't work.
SELECT a.SN, a.is_borrowed,a.max(date) as date, a.person
FROM table a
INNER JOIN (SELECT SN, MAX(date) as date, osoba from table where person like
"2" group by SN) as b
ON a.SN=b.SN and a.date=b.date
WHERE a.person like "2" and a.is_borrowed=1
If I correctly understood you from the question and the comment you made under it, here's one way to do it without specifying the person:
select *
from TableName as p
inner join (select max(borrow_date) as borrow_date,
SN
FROM TableName
where is_borrowed = 1
group by SN) as p2
on p.borrow_date = p2.borrow_date and p.SN = p2.SN
This should give you the result you're looking for. Here's a demo.
Note that I had to change the borrowed_date values in the table since yours contain hours and minutes while I didn't add those.
You can always specify it for each person by adding a where clause after the join.
select p.person,
p.borrow_date,
p.is_borrowed,
p.SN,
p.date,
p.id
from TableName as p
inner join (select max(borrow_date) as borrow_date,
SN
FROM TableName
where is_borrowed = 1
group by SN) as p2
on p.borrow_date = p2.borrow_date and p.SN = p2.SN
where p.person = '1'
Output:
person | borrow_date | is_borrowed | SN | date | id
1 | 2019-01-10 | 1 | 20 | 2019-01-10 | 6
1 | 2019-01-08 | 1 | 10 | 2019-01-08 | 4
While where p.person = '2' and where p.person = '3' will return empty sets.
I have a table A that contains tree columns, id, users ids and vehicle id. And a table B that contains vehicleid, and vehicle name.
Table A
---------------------------
| Id | User_id |Vehicle_id|
---------------------------
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 1 | 4 |
| 4 | 2 | 2 |
| 5 | 2 | 3 |
| 6 | 4 | 5 |
---------------------------
Table B
-------------------
| Id |Vehicle_name|
-------------------
| 1 | Car |
| 2 | Bike |
| 3 | Plane |
| 4 | Boat |
| 5 | Rocket |
-------------------
Given a user id, I need to get all vehicle names, that doesn't match with table A. I've tried Outer joins, but I can't manage to do get the info that i need.
For example: Given user id 1, the query should return Car and Rocket.
thanks in advance
This is simple enough using not in or not exists:
select b.*
from b
where not exists (select 1
from a
where a.vehicle_id = b.id and a.user_id = #a_user_id
);
I also thought of using a cross join and was able to get the output in case you are more comfortable with join logic.
SELECT CJOIN.USER_ID, CJOIN.VEHICLE_ID, CJOIN.VEHICLE_NAME
FROM
(SELECT DISTINCT A.USER_ID, B.ID AS VEHICLE_ID, B.VEHICLE_NAME FROM TABLE_A A CROSS JOIN TABLE_B B) CJOIN
LEFT JOIN
TABLE_A D
ON CJOIN.USER_ID = D.USER_ID AND CJOIN.VEHICLE_ID = D.VEHICLE_ID
WHERE D.USER_ID IS NULL AND D.VEHICLE_ID IS NULL;
First, I got all possible combinations of USER_ID x VEHICLE_ID by a cross join and used this table in a left join to pull records for which there is no match.
I have a basic table:
+-----+--------+------+------+
| id, | name, | cat, | time |
+-----+--------+------+------+
| 1 | jamie | 1 | 100 |
| 2 | jamie | 2 | 100 |
| 3 | jamie | 1 | 50 |
| 4 | jamie | 2 | 150 |
| 5 | bob | 1 | 100 |
| 6 | tim | 1 | 300 |
| 7 | alice | 4 | 100 |
+-----+--------+------+------+
I tried using the "Left Joining with self, tweaking join conditions and filters" part of this answer: SQL Select only rows with Max Value on a Column but some reason when there are records with a value of 0 it breaks, and it also doesn't return every unique answer for some reason.
When doing the query on this table I'd like to receive the following values:
+-----+--------+------+------+
| id, | name, | cat, | time |
+-----+--------+------+------+
| 1 | jamie | 1 | 100 |
| 4 | jamie | 2 | 150 |
| 5 | bob | 1 | 100 |
| 6 | tim | 1 | 300 |
| 7 | alice | 4 | 100 |
+-----+--------+------+------+
Because they are unique on name and cat and have the highest time value.
The query I adapted from the answer above is:
SELECT a.name, a.cat, a.id, a.time
FROM data A
INNER JOIN (
SELECT name, cat, id, MAX(time) as time
FROM data
WHERE extra_column = 1
GROUP BY name, cat
) b ON a.id = b.id AND a.time = b.time
The issue here is that ID is unique per row you can't get the unique value when getting the max; you have to join on the grouped values instead.
SELECT a.name, a.cat, a.id, a.time
FROM data A
INNER JOIN (
SELECT name, cat, MAX(time) as time
FROM data
WHERE extra_column = 1
GROUP BY name, cat
) b ON A.Cat = B.cat and A.Name = B.Name AND a.time = b.time
Think about it... So what ID is mySQL returning form the Inline view? It could be 1 or 3 and 2 or 4 for jamie. Hows does the engine know to pick the one with the max ID? it is "free to choose any value from each group, so unless they are the same, the values chosen are indeterminate. " it could pick the wrong one resulting in incorrect results. So you can't use it to join on.
https://dev.mysql.com/doc/refman/5.0/en/group-by-handling.html
If you want to use a self join, you could use this query:
SELECT
d1.*
FROM
date d1 LEFT JOIN date d2
ON d1.name=d2.name
AND d1.cat=d2.cat
AND d1.time<d2.time
WHERE
d2.time IS NULL
It is very simple
SELECT MAX(TIME),name,cat FROM table name group by cat
I am learning joins and have the following tables.
Student
| ID | NAME |
-------------
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
Pass
| ID | MARKS |
--------------
| 2 | 80 |
| 3 | 75 |
Fail
| ID | MARKS |
--------------
| 1 | 25 |
| 4 | 20 |
The output I want is this:
| NAME | MARKS |
----------------
| B | 80 |
| C | 75 |
| A | 25 |
| D | 20 |
I wrote a query like this:
select s.id,s.name,p.marks from student s
left join pass p on s.id=p.id
left join (select f.marks,f.id from fail f ) as nn on s.id=nn.id
order by marks desc;
The output I got is this:
| id | name | Marks|
--------------------
| 1 | B | 80 |
| 2 | C | 75 |
| 3 | A | Null |
| 4 | D | NUll |
Cant figure out why Null is coming. Any pointers?
You can use CASE statement for that:
SELECT Name,
CASE WHEN P.Marks IS NULL THEN f.Marks ELSE P.Marks END AS Marks
FROM Student s
LEFT JOIN Pass p ON s.ID = p.ID
LEFT JOIN Fail f ON s.ID = f.ID
ORDER BY Marks DESC;
Or you can also use IF statement:
SELECT Name,
IF(P.Marks IS NULL, F.Marks, P.Marks) AS Marks
FROM Student s
LEFT JOIN Pass p ON s.ID = p.ID
LEFT JOIN Fail f ON s.ID = f.ID
ORDER BY Marks DESC;
Output
| NAME | MARKS |
----------------
| B | 80 |
| C | 75 |
| A | 25 |
| D | 20 |
See this SQLFiddle
To learn more about JOINs see: A Visual Explanation of SQL Joins
You select only the passed marks, this is the reason of null-s appears near falied results.
If you want to select the failed marks you can use IF condition
select s.id,s.name,IF(p.marks = null, nn.marks, p.marks) as markss
from student s
left join pass p on s.id=p.id
left join fail nn on s.id=nn.id
order by markss desc;
Or you can use union of the passed and failed results.
select s.id,s.name, u.marks
from student s
left join ( (SELECT * FROM pass) UNION (SELECT * FROM fail) ) as n ON n.id = s.id
order by marks desc;
You need to understand how the different joins work to understand why you receive NULL for the marks column.
Take a look here:A Visual Explanation of SQL Joins
The relevant example for you is:
LEFT OUTER JOIN:
SELECT * FROM TableA
LEFT OUTER JOIN TableB
ON TableA.name = TableB.name
id name id name
-- ---- -- ----
1 Pirate 2 Pirate
2 Monkey null null
3 Ninja 4 Ninja
4 Spaghetti null null
The Null values you received for the marks column are rows that have no match in the left joined tables.
(the left part of the Venn diagram) the values that does have a value are the cross section between the tow groups of the Venn Diagram.
specifics for your example:
select s.id,s.name,p.marks
from student s
left join pass p on s.id=p.id
left join (select f.marks,f.id from fail f ) as nn on s.id=nn.id
order by marks desc;
The output i got is this:
id | name | Marks
-------------------
1 | B | 80
2 | C | 75
3 | A | Null
4 | D | NUll
This will return all student rows when.
students that have a passing gtade will display the grade and thous who don't will display null.
Try the below Query, use COALESCE
select s.id,s.name,COALESCE(p.marks , nn.marks) as marks
from student s
left join pass p on s.id=p.id
left join fail nn on s.id=nn.id
order by marks desc;
SQL Fiddle