I am having trouble with an SQL query. I have two tables.
My first table:
+------------+-------------+---------------+
| id_mission | Some column | Other column |
+------------+-------------+---------------+
| 1 | ... | ... |
| 2 | ... | ... |
+------------+-------------+---------------+
My second table:
+------------+-------------+---------+
| id_mission | id_category | points |
+------------+-------------+---------+
| 1 | 1 | 3 |
| 1 | 2 | 4 |
| 1 | 3 | 4 |
| 1 | 4 | 8 |
| 2 | 1 | -4 |
| 2 | 2 | 3 |
| 2 | 3 | 1 |
| 2 | 4 | -7 |
+------------+-------------+---------+
And I would like to have this kind of result with my SELECT request
+------------+-------------+--------------+---------------+----------------+
| id_mission | Some column | Other column | id_category 1 | id_category X |
+------------+-------------+--------------+---------------+----------------+
| 1 | ... | ... | ... | ... |
| 2 | ... | ... | ... | ... |
+------------+-------------+--------------+---------------+----------------+
I have tried this with the first two column but it doesn't work, I also tried GROUP_CONCAT, it works but it's not the result I want.
SELECT m.id_mission ,mc.id_category 1,mc1.id_category 2
from mission m
left join mission_category mc on m.id_mission = mc.id_mission
left join mission_category mc1 on m.id_mission = mc1.id_mission
Can someone help me?
You can use conditional aggregation. Assuming that you want to pivot the points value per category:
select
t1.*,
max(case when t2.id_category = 1 then points end) category_1,
max(case when t2.id_category = 2 then points end) category_2,
max(case when t2.id_category = 3 then points end) category_3
from t1
inner join t2 on t2.id_mission = t1.id_mission
group by t1.id_mission
This assumes that id_mission is the primary key of t1 (else, you need to enumerate the columns you want in both the select and group by clauses).
Related
table 1: forum_threads
+-----+------+-------+
| id | title| status|
+-----+------+-------+
| 1 | a | 1 |
| 2 | b | 1 |
| 3 | c | 1 |
| 4 | d | 1 |
| 5 | e | 1 |
| 6 | f | 1 |
+-----+------+-------+
table 2: forum_comments
+-----+----------+--------------------+
| id | thread_id| comment |
+-----+----------+--------------------+
| 1 | 4 | hai |
| 2 | 4 | hello |
| 3 | 2 | welcome |
| 4 | 2 | whats your name |
| 5 | 6 | how are you |
| 6 | 5 | how old are you |
| 7 | 5 | good |
+-----+----------+--------------------+
wanted output
+-----------+----------+-----------------+
| thread_id | title | comment_count |
+-----------+----------+-----------------+
| 5 | e | 2 |
| 6 | f | 1 |
| 2 | b | 2 |
| 4 | d | 2 |
+-----------+----------+-----------------+
my Query
SELECT forum_threads.*,forum_comments.*,count(forum_comments.id) as comment_count
FROM forum_comments
LEFT JOIN forum_threads ON forum_comments.thread_id = forum_threads.id
GROUP BY forum_threads.id
ORDER BY forum_comments.id desc
Here I am trying to get the titles by the latest comment.
when I give ORDER BY forum_comments.id this returns the wrong order.
I need to order by the latest comments in the forum_comments table.
this query returns the wrong order please help me to find out the correct order.
how could I solve this easily?
This query should give you the expected result:
select t2.thread_id, t1.title, t2.comment_count from forum_threads as t1,
(SELECT id, thread_id, count(comment) as comment_count from forum_comments group by thread_id) as t2
where t1.id = t2.thread_id order by t2.id desc;
Instead of using forum_threads.* and forum_comments.* can you give specific column names and try.
If that doesn't work you should try explicitly assigning primary and foreign keys.
How to select rows which are not defined? Like row 2 have undefined day 3 and row 3 have undefined day 1. I want them to be 0 in result set.
+----+-----+-------+
| id | day | count |
+----+-----+-------+
| 1 | 1 | 262 |
| 1 | 2 | 685 |
| 1 | 3 | 984 |
| 2 | 1 | 692 |
| 2 | 2 | 962 |
| 3 | 2 | 355 |
| 3 | 3 | 741 |
+----+-----+-------+
EDIT:
I want select count from days 1, 2 and 3 (not whole table) and display 0 on undefined day.
We can get all unique id values in a Derived Table.
For day, you seem to want only 1,2 and 3 only. So we can directly consider these values only using UNION ALL.
CROSS JOIN between them to get all possible combinations.
LEFT JOIN from all_combinations table to the main table on id and day.
We can use Coalesce() function to consider 0 value for count, for the cases where there is no matching row in the main table
Try the following:
SELECT all_combinations.id,
all_combinations.day,
COALESCE(t.count, 0) AS count
FROM
(
SELECT ids.id, days.day
FROM
(SELECT DISTINCT id FROM your_table) AS ids
CROSS JOIN
(SELECT 1 AS day UNION ALL SELECT 2 UNION ALL SELECT 3) AS days
) AS all_combinations
LEFT JOIN your_table AS t
ON t.id = all_combinations.id AND
t.day = all_combinations.day
Result:
| id | day | count |
| --- | --- | ----- |
| 1 | 1 | 262 |
| 2 | 1 | 692 |
| 3 | 1 | 0 |
| 1 | 2 | 685 |
| 2 | 2 | 962 |
| 3 | 2 | 355 |
| 1 | 3 | 984 |
| 2 | 3 | 0 |
| 3 | 3 | 741 |
View on DB Fiddle
I have a number of tables in my database.
Table: ObjectToPerson
For example if I had a number of entries below in the database:
+----+------------+------------+----------+----------+--------------+
| Id | WeekNumber | Date | PersonId | ObjectId | ObjectTypeId |
+----+------------+------------+----------+----------+--------------+
| 1 | 1 | 2015-11-04 | 1 | 1 | 1 |
| 2 | 1 | 2015-11-04 | 1 | 3 | 2 |
| 3 | 1 | 2015-11-04 | 2 | 2 | 1 |
| 4 | 1 | 2015-11-04 | 2 | 4 | 2 |
+----+------------+------------+----------+----------+--------------+
I am wanting to return the results back as two lines as follows:
+------+------------+----------+----------------------------+----------------------------+
| Week | Date | PersonId | ObjectId(ObjectTypeId = 1) | ObjectId(ObjectTypeId = 2) |
+------+------------+----------+----------------------------+----------------------------+
| 1 | 2015-11-04 | 1 | 1 | 3 |
| 1 | 2015-11-04 | 2 | 2 | 4 |
+------+------------+----------+----------------------------+----------------------------+
I am thinking of some sort of Group By query but I just can't seem to get it right.
Select * From ObjectToPerson
Left Join Objects O On O.Id = ObjectToPerson.ObjectId And ObjectToPerson.ObjectTypeId = 1
Left Join Objects O On O.Id = ObjectToPerson.ObjectId And ObjectToPerson.ObjectTypeId = 2
Can someone explain how I would get to this please?
You could use CASE to only select the ObjectId if the type is correct for the column, then use MAX/GROUP BY to group the result into a single row per person/week/date.
SELECT WeekNumber week, date, personid,
MAX(CASE WHEN ObjectTypeId=1 THEN ObjectId END) Type1,
MAX(CASE WHEN ObjectTypeId=2 THEN ObjectId END) Type2
FROM ObjectToPerson
GROUP BY week, date, personid
An SQLfiddle to test with.
You don't want two joins, you want a WHERE clause;
SELECT * FROM ObjectToPerson
LEFT JOIN Objects O ON O.Id = ObjectToPerson.ObjectId
WHERE ObjectToPerson.ObjectTypeId IN(1,2)
I have one table like this:
+----+---------+-------------+
| id | site_id | search_term |
+----+---------+-------------+
| 1 | 2 | apple |
| 2 | 2 | banana |
| 3 | 3 | cheese |
| 4 | 1 | aubergine |
+----+---------+-------------+
And another like this:
+----+---------+-------------+
| id | site_id | search_term |
+----+---------+-------------+
| 1 | 2 | 1 |
| 2 | 2 | 2 |
| 3 | 2 | 1 |
| 4 | 2 | 1 |
| 5 | 3 | 3 |
| 6 | 1 | 4 |
+----+---------+-------------+
I want to find out how many times each search_term shows up in the 2nd table, and how many times.
In other words, from this data, if I was asking about site_id 2, I'd want this to be returned:
+-------------+-------+
| search_term | count |
+-------------+-------+
| apple | 3 |
| banana | 1 |
+-------------+-------+
I'm familiar with basic joins and such, as well as COUNT, but I'm not sure how to count things from another table.
Thanks!
You could join the tables together, and count the number of rows in the second table:
select t1.search_term
, count(t2.id)
from table1 t1
left join table2 t2
on t1.id = t2.search_term
group by t1.search_term
Give this a try:
select t1.search_term, count(*) from t1
join t2 on t1.id = t2.search_term and t1.site_id = t2.site_id
where t1.site_id = 2
group by t1.search_term
What I did was, I wanted each user to have their own "unique" numbering system. Instead of auto incrementing the item number by 1, I did it so that Bob's first item would start at #1 and Alice's number would also start at #1. The same goes for rooms and categories. I achieved this by creating "mapping" tables for items, rooms and categories.
The query below works, but I know it can definitely be refactored. I have primary keys in each table (on the "ids").
SELECT unique_item_id as item_id, item_name, category_name, item_value, room_name
FROM
users_items, users_map_item, users_room, users_map_room, users_category, users_map_category
WHERE
users_items.id = users_map_item.map_item_id AND
item_location = users_map_room.unique_room_id AND
users_map_room.map_room_id = users_room.room_id AND
users_map_room.map_user_id = 1 AND
item_category = users_map_category.unique_category_id AND
users_map_category.map_category_id = users_category.category_id AND
users_category.user_id = users_map_category.map_user_id AND
users_map_category.map_user_id = 1
ORDER BY item_name
users_items
| id | item_name | item_location |item_category |
--------------------------------------------------------
| 1 | item_a | 1 | 1 |
| 2 | item_b | 2 | 1 |
| 3 | item_c | 1 | 1 |
users_map_item
| map_item_id | map_user_id | unique_item_id |
----------------------------------------------------
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
users_rooms
| id | room_name |
----------------------
| 1 | basement |
| 2 | kitchen |
| 3 | attic |
users_map_room
| map_room_id | map_user_id | unique_room_id |
----------------------------------------------------
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
users_category
| id | room_name |
----------------------
| 1 | antiques |
| 2 | appliance |
| 3 | sporting goods |
users_map_category
| map_room_id | map_user_id | unique_category_id |
----------------------------------------------------
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
Rewriting your query with explicit JOIN conditions makes it more readable (while doing the same).
SELECT mi.unique_item_id AS item_id
, i.item_name
, c.category_name
, i.item_value
, r.room_name
FROM users_map_item mi
JOIN users_items i ON i.id = mi.map_item_id
JOIN users_map_room mr ON mr.unique_room_id = i.item_location
JOIN users_room r ON r.room_id = mr.map_room_id
JOIN users_map_category mc ON mc.unique_category_id = i.item_category
JOIN users_category c ON (c.user_id, c.category_id)
= (mc.map_user_id, mc.map_category_id)
WHERE mr.map_user_id = 1
AND mc.map_user_id = 1
ORDER BY i.item_name
The result is unchanged. Query plan should be the same. I see no way to improve the query further.
You should use LEFT [OUTER] JOIN instead of [INNER] JOIN if you want to keep rows in the result where no matching rows are found in the right hand table. You may want to move the additional WHERE clauses to the JOIN condition in this case, as it changes the outcome.