Can't SELECT records from two tables properly - mysql

I've been using this Query at first, Then used this Query at last
Which are
##Query[1]
SELECT t.title, p.content, p.version
FROM drafts d
INNER JOIN titles t ON t.id = d.tp_id AND d.t = 1
INNER JOIN posts p ON p.id = d.tp_id AND d.t = 2
WHERE user_id = 1
##Query[2]
SELECT coalesce(p.title, t.title), p.content, p.version
FROM drafts d
INNER JOIN titles t ON t.id = d.tp_id AND d.t = 1
INNER JOIN
(
SELECT pt.id, tp.title, pt.content, pt.version
FROM posts pt
INNER JOIN titles tp ON tp.id = pt.tid
) p ON p.id = d.tp_id AND d.t = 2
WHERE user_id = 1
What I want to do Using the Table: drafts to use
Column: tp_id as an identifier to the Column: id in other tables.
Column: user_id as the id of the user having the draft.
Column: t as the identifier to which table of Tables: titles[t=1], posts[t=2] to fetch the records from it.
In Table: posts the Column: tid links to the Column: id of Table: titles Which is used to pull the Column: title.
I want no records to be shown from the Table: titles if doesn't exist, And no records to be shown from the Table: posts if the title related using tid on Table: titles doesn't exist Or the record of the Table: posts doesn't exist, That why I used INNER JOIN.
But in both queries I don't get any results at all.
Is this even the proper table scheme and design to be used for something like the Drafts table for two different tables instead of one for each table?
The result I expect is something like this
title content version
TheTitle null null
TheTitle Content1 1
TheTitle Content2 2
TheTitle Content3 3
TheTitle Content4 4
TitleThe Content1 1
TitleThe Content2 2
TitleThe Content3 3
TitleThe Content4 4
A simple Example:
[table-a] [table-b]
[id - title ] [id - table_a_id - content ]
[1 - title-1] [1 - 1 - content-1]
table-a has the titles.
table-b has the content of each
title.
table-b column of table_a_id links the content with
the title of table-a.
[table-ab]
[user_id - table_col_id - table_letter]
[1 - 1 - a ]
[1 - 1 - b ]
table-ab has user_id to tell which user will be shown the records.
table-ab has table_letter to tell the query which table to fetch the data from it.
What I want the Query to do is to check table-ab and fetch the data from the other tables according to it, so it would be
table_letter = a => fetching rows from table-a.
table_col_id = 1 => fetching rows from table-a WHERE id = 1.
result = title-1
table_letter = b => fetching rows from table-b.
table_col_id = 1 => fetching rows from table-b WHERE id = 1.
result = title-1 - content-1
Final result:
id - title - content
-------------------------
1 - title-1 - null
2 - title-1 - content-1

Do two separate queries (for t=1 and t=2) and use UNION ALL to combine the results:
SELECT t.title, null content , null version
FROM drafts d
INNER JOIN titles t
ON t.id = d.tp_id
WHERE d.user_id = 1 and d.t = 1
UNION ALL
SELECT pt.title, pt.content, pt.version
FROM drafts d
INNER JOIN
( SELECT p.id, t.title, p.content, p.version
FROM posts p
INNER JOIN titles t ON t.id = p.tid ) pt
ON pt.id = d.tp_id AND d.t = 2
WHERE d.user_id = 1

As you are using inner join so please check the following:
Common data in both tables(joining column), if there will not be any common value it will not pick any thing.
Check data type of the column which are used to join both table that should be same if not then handle it
Extra spaces in the joining column.

After joining with condition d.t = 1 there is no data for d.t = 2 That's why after 2nd Join you are not getting any data. Try the below Query
SELECT coalesce(p.title, t.title), p.content, p.version
FROM drafts d
INNER JOIN titles t
ON t.id = d.tp_id
INNER JOIN
(
SELECT pt.id, tp.title, pt.content, pt.version
FROM posts pt
INNER JOIN titles tp
ON tp.id = pt.tid
) p
ON p.id = d.tp_id
WHERE user_id = 1
AND (d.t = 1 OR d.t = 2)

This will produce almost exactly what you have in your question. It does omit the line with the null values for the content and version. Not sure why that would have been in the expected output.
SELECT
if(d.t = 1,tp.title, if(d.t = 2,t.title,"")) as `title`,
p.content,
p.version
FROM drafts d
LEFT JOIN titles t ON t.id = d.tp_id AND d.t = 2
LEFT JOIN posts p ON t.id = p.tid
LEFT JOIN titles tp ON tp.id = p.tid AND d.t = 1
WHERE user_id = 1 AND NOT p.content IS NULL
I changed some of the data, specifically the groups of Content1 - Content4. I added "a" to the first 4, and "b" to the remainder.
Here's a SQL Fiddle that shows what it does.

Related

SQL Query: Joining 4 tables to one

I tried all the similar questions but I can not get what I want.
Need help with Joining the table.
1. Table bookings:
id = 1 customer_id = 1 booking_details = 'venue etc'
2. Table customers:
id = 1 name = 'John Citizen'
3. Table: booking_objects:
id = 1 booking_id = 1 object_id = 1
id = 2 booking_id = 1 object_id = 2
4. Table objects:
id = 1 name = 'Object 1'
id = 2 name = 'Object 2'
I want to join tables to I get "Venue etc, Jhon Citizen, Oject 1, Object 2"
currently I am getting "Venue etc, Jhon Citizen" using below query
$this->db->select("bookings.bookig_details, customers.name as customer_name, objects.name as object_name")->join("customers", "customers.id = bookings.customer_id", "left outer")
In your requirement, Venue etc, Jhon Citizen, Object 1, Object 2 are mentioned. Object 1 and Object 2 comes under same column i.e, objects.name.
As per my understanding you need booking_details, customer_name, obj_name are your required columns.
select b.booking_details, c.name as customer_name, o.name as obj_name
bookings b
inner join
customers c
on b.customer_id = c.id
inner join
booking_objects bo
on b.id = bo.id
inner join
objects o
on bo.object_id = o.id
You can change the join types based on your requirement.
Instead of using values of the required output, it would have been better to use required columns in your question for clarity.
You need to use Self JOIN
like this.
select b.booking_details,c.name 'customer_name',o1.name 'o1Name',o2.name 'o2Name'
FROM objects o1
join objects o2 ON o1.id = 1 and o2.id = 2
join booking_objects bo on o1.id = bo.object_id
join bookings b on b.customer_id = bo.booking_id
join customers c on bo.booking_id = c.ID
sqlfiddle:http://sqlfiddle.com/#!9/594973/14

SQL query returns column with data from another column

I have a table Notices connected to tables Likes and Comments. When I return the notices for a user I also create columns: number_of_likes, number_of_comments and liked_by_me. The query is working correctly when the user making the query hasn't liked a notice (liked_by_me = 0) . But if they have (liked_by_me = 1) the value I get for number_of_likes is wrong and is the same as number_of_comments.
Example:
1)
- liked by me = false
- likes = 1
- comments = 5
Returned values:
- liked_by_me = 0
- number_of_likes = 1
- number_of_comments = 5
2)
- liked by me = true
- likes = 2
- comments = 5
Returned values:
- liked_by_me = 1
- number_of_likes = 5
- number_of_comments = 5
Here is the query I am using:
SELECT notices.*
, count(comment.id) as number_of_comments
, count(like1.user_id) as number_of_likes
, like2.user_id IS NOT NULL AS liked_by_me
, boards.name as board_name
FROM notices
LEFT JOIN comments as comment
ON (comment.notice_id = notices.id)
LEFT JOIN likes as like1
ON (like1.notice_id = notices.id)
LEFT JOIN likes as like2
ON (like2.notice_id = notices.id
AND like2.user_id = $1)
LEFT JOIN boards
ON (boards.id = notices.board_id)
LEFT OUTER JOIN board_users
ON (board_users.board_id = notices.board_id)
WHERE board_users.user_id = $1
GROUP BY notices.id
, boards.name
, like2.user_id
, userId
Any help would be appreciated. I have been on this for hours and I don't think I will be able to find the problem.
Thanks!
Solution:
Here is the working query
SELECT notices.*,
(SELECT COUNT(user_id) from likes WHERE likes.notice_id = notices.id) AS number_of_likes,
(SELECT user_id IS NOT NULL from likes WHERE likes.notice_id = notices.id AND likes.user_id = $1) AS liked_by_me,
count(comments.id) as number_of_comments, boards.name as board_name
FROM notices LEFT JOIN comments ON (comments.notice_id = notices.id)
LEFT JOIN boards ON (boards.id = notices.board_id)
LEFT OUTER JOIN board_users ON (board_users.board_id = notices.board_id)
WHERE board_users.user_id = $1 GROUP BY notices.id, boards.name", user);
You will have to use subeselects.
Excellent article on this problem: The GROUPing pitfall
TL;DR: Basically, you have to realize, that all your comments and likes are being multiplicated by one another. Try to display the result of the query without the group clause to see, that duplicate likes/comments are being counted.
EDIT: I didn't test this, but it's how the query might look:
(that is if user can only like one notice once, otherwise you would have to group current user likes too)
SELECT
notices.*,
comments.number_of_comments,
likes.number_of_likes
current_user_likes.user_id IS NOT NULL AS liked_by_me
boards.name AS board_name
FROM notices
LEFT JOIN (
SELECT
COUNT(*) AS number_of_comments,
notice_id
FROM comments
GROUP BY notice_id
) AS comments ON comments.notice_id = notices.id
LEFT JOIN (
SELECT
COUNT(*) AS number_of_likes,
notice_id
FROM likes
GROUP BY notice_id
) AS likes ON likes.notice_id = notices.id
LEFT JOIN likes AS current_user_likes
ON current_user_likes.notice_id = notices.id
AND current_user_likes.user_id = $1
LEFT JOIN boards ON boards.id = notices.board_id
INNER JOIN board_users
ON board_users.board_id = notices.board_id
AND board_users.user_id = $1;

MySQL Extracting data from 3 tables

First of all apologies for the newbee question, I am totally new to MySQL.
I have 3 tables with some fields. The relevant fields for the query are as follows:
table 1 - Registration
user_name
user_email
ID
table 2 - photogallery
ID
user_id
Status
photo_url
table 3 - photovote
Photo_ID
status
I need a list of all the votes (1 record per vote) with explicited data of the photo and the user owning that photo. This means that Photo_ID in photovote is = to ID in photogallery and user_id in photogallery is = ID in Registration.
What I came up with is
SELECT *
FROM photovote
LEFT JOIN (photogallery, registration)
ON photovote.Status = 1
AND photogallery.Status = 1
WHERE photovote.user_id = photogallery.user_id
AND photogallery.user_id = registration.ID
But it really does'nt do the job. Anyone can point me to the right direction maybe?
Thanks a lot.
Andrea
SELECT *
FROM photovote v
INNER JOIN photogallery g ON v.PhotoId = g.ID
INNER JOIN registration r ON g.user_id = r.ID
WHERE v.Status = 1
AND g.Status = 1
SELECT r.user_name, r.user_email, p.status, p.photo_url, pv.status as pv_status FROM registration r LEFT JOIN photogallery p ON (r.id=p.id) LEFT JOIN photovote pv ON (pv.id=p.id) WHERE p.status = 1 AND pv_status = 1

Find Record if value does not exist?

I am having problem with the SQL Query.
I want to find StatusID = 1 in the records table IF StatusID = 2 does not exist.
I have tried the query:
SELECT * FROM records AS A
LEFT JOIN records AS B on B.StoreID = A.StoreID
WHERE A.StatusID = 1 AND B.StatusID != 2
It is still showing the result even if StatusID = 2 is exist.
Note: StoreID are the ref id in the records table.
You want to use NOT EXISTS:
SELECT *
FROM records AS A
WHERE A.StatusID = 1
AND NOT EXISTS (select B.StoreID
from records AS B
where B.StoreID = A.StoreIDB
and B.StatusID = 2)
Assumming non-null StatusID field (is always filled in):
SELECT * FROM records AS A
LEFT JOIN records AS B
on B.StoreID = A.StoreID
and B.StatusID = 2
WHERE A.StatusID = 1 AND B.StatusID IS NULL
You're still seeing the result even if StatusID = 2 exists because you're using a LEFT JOIN, which as you'll remember returns the entire left set and all matching entries from the right set or a NULL where none exist.
Seems to me the easiest fix is to just use an INNER JOIN, since for the cases LEFT JOIN will return that INNER JOIN won't, StatusID will equal neither 1 nor 2.
Thus:
select * from records a
inner join records b
on b.storeid = a.storeid
where a.statusid = 1
and b.statusid <> 2

In an HABTM relation, how can find items that must meet more then one criteria on the related table

Hope someone understood the title...
Let's say I have the following relation, Animals HABTM Tags.
animals table
id name
1 dog
2 whale
3 Elephant
tags table:
id name
1 brown
2 gray
3 terrestrial
4 aquatic
the link table
animal_id tag_id
1 1
1 3
2 2
2 4
3 2
3 3
I'd like to retrieve all animals that have Tag = gray AND Tag = aquatic
It is easy with only one criteria
SELECT * FROM `animals` as a
left join animals_tags at on a.id = at.animal_id
Where at.tag_id = (select id from tags where name = 'brown')
Is it possible to make a single query for more then one tag? Or should I retrieve results for each tags and then extract the intersecting results?
Note: I user tag ids instead of tag names.
If you want to select 1 row per animal:
SELECT a.*, GROUP_CONCAT(t.name) tags
FROM `animals` as a
LEFT JOIN animals_tags at ona.id = at.animal_id
LEFT JOIN tags t ON at.tag_id = t.id
GROUP BY a.id
HAVING SUM(at.tag_id = 1) > 0 AND SUM(at.tag_id = 4) > 0
If you also want to retrieve all the tags for each animal:
SELECT a.*, t.*
FROM animals a JOIN (
SELECT animal_id
FROM animals_tags
GROUP BY animal_id
HAVING SUM(tag_id = 1) > 0 AND SUM(tag_id = 4) > 0
) ag ON a.id = ag.animal_id
LEFT JOIN animals_tags at ON a.id = at.animal_id
LEFT JOIN tags t ON at.tag_id = t.id
INTERSECT would be nice if MySQL had it, but you could accomplish this with a HAVING clause, in theory.
SELECT a.name FROM `animals` as a
left join animals_tags at ona.id = at.animal_id
Where at.tag_id = (select id from tags where name = 'brown')
OR at.tag_id = (select id from tags where name = 'terrestrial')
GROUP BY a.name
HAVING COUNT(a.name) = 2