left join issue with mysql - php

I have two tables and trying to join both of them based on primary and foreign key.But the problem is that in second table the foreign key has multiple duplicate rows.
Structure :-
1 Table - category
catid catname
1 AAA
2 BBB
3 CCC
2 Table - answers
ansid catid userid
1 1 9
2 1 9
3 2 9
4 2 6
The result should be
userid catid catname present in answers table
null 1 AAA no
6 2 BBB yes
null 3 CCC no
My query is
SELECT a.userid, c.catid,c.catname,
case when sum(a.catid is not null) > 0
then 'yes' else 'no' end as present_in_answers_table
from answers a left join
category c on c.catid = a.catid
where (a.userid = 6) group by c.catid
But it is not returning the results what I want.It returns only one row that is
userid catid catname present in answers table
6 2 BBB yes

I think you need to switch the order of the joins, so you keep everything in the category table and then move the where condition to the on clause:
SELECT a.userid, c.catid, c.catname,
(case when count(a.catid) > 0 then 'yes' else 'no'
end) as present_in_answers_table
from category c left join
answers a
on c.catid = a.catid and
a.userid = 6
group by c.catid;
Note that I also changed the sum() to a count() -- count() automatically counts the number of times the argument is not NULL.

Related

Projecting mySQL database, how to deal with multiple categories

I need a help with projecting my database. The purpose of this database will be to show offers in different categories. There are 1-6 categories to each item. There are around 80 categories types, so I decided to make three tables as below:
table1:
ID Item_id
1 1
2 2
3 3
4 4
5 5
table2:
ID Item_id Category
1 1 cat55
2 1 cat56
3 1 cat57
4 1 cat58
5 2 cat42
6 2 cat43
7 2 cat44
8 2 cat45
9 3 cat42
etc.
table3:
Category_id category_name
cat55 apples
cat56 oranges
cat57 bananas
cat58 pineapples
Am I doing this right? I've got a problem to make proper sql query to show my categories in php, because when I use this query:
SELECT table1.*, table2.*, table3.*
FROM table1
INNER JOIN table2
ON table1.item_id = table2.item_id
INNER JOIN table3
ON table2.category=table3.category_id
It only gives me the first category name, when I need all of them and show them like this:
Item 1: apples, oranges, bananas, pineapples
Item 2: cat42, cat43, cat44, cat45
Item 3: cat42
What am I doing wrong? Is it wrong query or I need to change the database structure to like this
table 1 and 3 unchanged
table 2:
ID Item_id c1 c2 c3 c4 c5 c6
1 1 cat55 cat56 cat57 cat58 null null
2 2 cat42 cat43 cat44 cat45 null null
3 3 cat42 null null null null null
I'm using foreach loop, so I can do only one query, I know that more queries are possible, but I need to make it as simple as possible.
If you want to fetch all names in single row for each item, following query will work:
SELECT table1.Item_Id,Group_Concat(t3.category_name separator ',') as Category_Name
FROM table1
INNER JOIN table2
ON table1.item_id = table2.item_id
INNER JOIN table3
ON table2.category=table3.category_id
Group by table1.Item_Id;
I don't find any problem in your DB Structure.
Hope it helps!

Mysql Query Join two table Order by one table column

I have two table (table 1 and table 2) . I want to show all the rows from table1 by joining with table2 which have multiple rows with same table1 id (foreign key relation) and will sort the result by table2 priority column (order by desc).
Table1
Table2
Result will be
thanks in advance
Edit
Table1
id name
1 test1
2 test2
3 test5
4 test7
5 test9
6 test3
Table2
id table1_id event priority
1 2 abc 0
2 2 kbc 0
3 2 abc 2
4 2 kbc 1
5 4 fgg 2
6 4 dss 3
7 1 fgfg 2
8 5 fgfg 2
9 6 xcxc 1
10 6 fgfh 3
Result
id_table1 name event priority
4 test7 dss 3
6 test3 fgfh 3
2 test2 abc 2
1 test1 fgfg 2
5 test9 fgfg 2
3 test5 NULL NULL
In the question you mentioned you need to select the data where id from table1 is available more than once in the table2 which does not match with the result set you gave.
Considering the original requirement the following should do the trick
select
t2.table1_id as id_table1,
t1.name,
t2.priority,
t2.event
from table1 t1
join
(
select
p1.table1_id,
p1.event,
p2.priority
from table2 p1
join(
select
max(priority) as priority,
table1_id
from table2
group by table1_id having count(*) > 1
)p2
on p2.table1_id = p1.table1_id and p2.priority = p1.priority
)t2
on t1.id = t2.t1id
order by t2.priority desc
Here is a demo
The result will get the same event corresponding the max priority column
This will get the result set that you want. You mentioned that you only need the items table1 ids that reflects more than once but result query shows tableid1 "1" even though it is only present once:
SELECT DISTINCT t1.id,t1.name ,t2.event, t2.priority
FROM TABLE2 t2
right join
TABLE1 t1
on t1.id=t2.table1_id
order by t2.priority desc
Try this query:
SELECT t1.*,t2.priority FROM table1 t1
INNER JOIN table2 t2
ON t1.id=t2.id
ORDER BY t2.priority DESC
Primary key and foreign key should have the same name. The syntax should be
SELECT Table1.id_table1,Table1.name,Table2.event,Table.priority FROM
Table1 LEFT JOIN Table2 ON
Table1.id=Table2.id
ORDER BY Table2.priority DESC
Make the following changes in Table2:
Get rid of the first column or rename it
Rename second column(your foreign key) to "id".

MySQL Query for Advanced Search multiple criteria

I'm working through an advanced search query where users select checkboxes based on multiple criteria. I'm a beginner so I'm hoping I can find out if I'm on the right track. I'm aware the query is quite the mess.
Edit: I realized this needed to be two questions, so I've revised to be strictly a query question
Table data
Table ss_users
user_id first_name last_name admin_level user_approved
1 nick jones 0 1
2 johnny rocket 0 1
Table ss_user_profile_status
user_id photo_uploaded
1 1
2 1
Table ss_user_photos
photo_id user_id filename selected
1 1 photo_1.jpg 1
2 2 photo_2.jpg 0
3 2 photo_2.jpg 1
Table ss_general
user_id city state zip neighborhood
1 baltimore maryland 00125 hamsterdam
2 lakeland maine 11542 treemont
Table ss_languages
user_id french german italian spanish
1 0 1 0 1
2 0 0 1 1
Table ss_experience
user_id waldorf kumon homeschooling
1 0 1 0
2 0 0 1
My current results are all users, which should not be the case:
SELECT
ss_users.*, ss_user_profile_status.*, ss_user_photos.*, ss_general.*,
ss_languages.*, ss_experience.*, ss_users.user_id AS userID,
ss_user_profile_status.user_id, ss_languages.user_id AS langID
FROM
ss_users
JOIN
ss_user_profile_status ON ss_users.user_id = ss_user_profile_status.user_id
LEFT JOIN
ss_user_photos ON ss_users.user_id = ss_user_photos.user_id
AND
ss_user_photos.selected = 1
LEFT JOIN
ss_languages ON ss_users.user_id = ss_languages.user_id
LEFT JOIN
ss_general ON ss_users.user_id = ss_general.user_id
LEFT JOIN
ss_experience ON ss_users.user_id = ss_experience.user_id
WHERE
ss_users.user_id = ss_user_profile_status.user_id
AND
ss_general.neighborhood_select LIKE '%hamsterdam%'
OR
ss_languages.spanish = 1
OR
ss_experience.kumon = 1
AND
ss_users.sitter_approved = 1
AND
ss_users.admin_level = 0
GROUP BY
ss_users.user_id DESC
For the output I need to represent much of the users profile, that's why I'm selecting a lot of table data, as well as the extra joins.
For your big fat SQL selection
SELECT
ss_users.*, ss_user_profile_status.*, ss_user_photos.*, ss_general.*,
ss_languages.*, ss_experience.*, ss_users.user_id AS userID,
ss_user_profile_status.user_id, ss_languages.user_id AS langID
FROM ss_users
JOIN ss_user_profile_status ON ss_users.user_id = ss_user_profile_status.user_id
LEFT JOIN ss_user_photos ON ss_users.user_id = ss_user_photos.user_id AND ss_user_photos.selected = 1
LEFT JOIN ss_languages ON ss_users.user_id = ss_languages.user_id
LEFT JOIN ss_general ON ss_users.user_id = ss_general.user_id
LEFT JOIN ss_experience ON ss_users.user_id = ss_experience.user_id
WHERE
( ss_general.neighborhood_select LIKE '%hamsterdam%' OR ss_languages.spanish = 1 OR ss_experience.kumon = 1 ) AND ss_users.sitter_approved = 1 AND ss_users.admin_level = 0
I only edit few places like adding bracket around the OR and remove the first condition cause it seems redundant, and also remove the group by since it will left some data out

Mysql select that matches all array elements [duplicate]

This question already has an answer here:
Select all rows that have at least a list of features
(1 answer)
Closed 9 years ago.
I have a mysql table
Table A
--------------------
item_id category_id
--------------------
1 1
1 2
1 4
2 1
2 3
Would like to make an sql query that will select all matches in an array
example:
given category_ids are 1,4 it should return only item_id 1
given category_ids are 1 it should return item_id 1 and 2
Thanks
For categories 1, 4:
SELECT item_id, COUNT(*) c
FROM TableA
WHERE category_id IN (1, 4)
GROUP BY item_id
HAVING c = 2
For category 1:
SELECT item_id, COUNT(*) c
FROM TableA
WHERE category_id IN (1)
GROUP BY item_id
HAVING c = 1
I think you should be able to see the pattern -- the HAVING clause should match the number of categories.
This assumes that item_id, category_id is unique in the table.
given category_ids are 1,4
SELECT item_id, category_id
FROM TableA
WHERE category_id IN (1, 4)
given category_ids are 1
SELECT item_id, category_id
FROM TableA
WHERE category_id IN (1)

Help with limiting a joined mysql database query

I have written a query which returns all records with some many-to-many joins correctly for the entire set or an individual article using WHERE a.id = ?
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id
LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id
LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id
LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
BUT!
I've hit a brick wall trying to work out how to limit the articles to a specific number of IDs, for working with pagination.
I'm ideally trying to use as simple and clear SQL statements as possible because I'm using the codeigniter framework with their active record class.
http://codeigniter.com/user_guide/database/active_record.html
Would really appreciate some help as I don't want to revert to using multiple queries for this as I've tried to reduce it down to a single query for database efficiency.
Have search around and tried some alternatives but nothing seems to work. Many thanks!
For example the results I return are like this
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
2 test 2 2 1 1
2 test 2 1 2 1
2 test 2 1 1 2
2 test 2 5 1 1
2 test 2 8 1 1
2 test 2 1 4 1
2 test 2 1 4 2
I need the results like this so that I can create sub-arrays in the php like this:
$articles = $query->result_array();
$output = array();
foreach ($articles as $article) {
// set up article details
$article_id = $article['id'];
// add article details
$output[$article_id]['article_id'] = $article_id;
$output[$article_id]['date_added'] = $article['date_added'];
$output[$article_id]['title'] = $article['title'];
$output[$article_id]['content'] = $article['content'];
// set up people details and add people array with details if exists
if (isset($article['person_id'])) {
$person_id = $article['person_id'];
$output[$article_id]['people'][$person_id]['person_id'] = $person_id;
$output[$article_id]['people'][$person_id]['lastname'] = $article['lastname'];
$output[$article_id]['people'][$person_id]['firstname'] = $article['firstname'];
}
// set up organizations details and add organizations array with details if exists
if (isset($article['organization_id'])) {
$organization_id = $article['organization_id'];
$output[$article_id]['organizations'][$organization_id]['organization_id'] = $organization_id;
$output[$article_id]['organizations'][$organization_id]['organization_name'] = $article['organization_name'];
}
// set up categories details and add categories array with details if exists
if (isset($article['category_id'])) {
$category_id = $article['category_id'];
$output[$article_id]['categories'][$category_id]['category_id'] = $category_id;
$output[$article_id]['categories'][$category_id]['category_name'] = $article['category_name'];
}
}
But if I just use LIMIT (with offset etc) 1
the results I get are
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
instead of
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
which is my desired result.
OK, so finally I worked out how it is possible.
Thought i'd include it here in case anyone else has the same problem.
Changing this line
FROM articles AS a
to this
FROM (SELECT * FROM articles LIMIT 5,3) AS a
does what I wanted.
So, why don't you use OFFSET 0,10 and LIMIT *number_of_results* in the SQL Query? (if I understood the question)
Specific number of IDs... WHERE ID IN (2,4,6,8)... ?
Are you using codeigniter's pagination?
http://codeigniter.com/user_guide/libraries/pagination.html
You can easily limit the number of records that are being returned using the MySQL LIMIT clause. This can be achieved like the following with your sample query.
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
LIMIT 10
Where 10 is the number of records you wish to display. The MySQL LIMIT clause allows you to specify a limit of the number of records and an initial offset. Like so:
LIMIT <offset>,<limit>
In your case <offset> would be the current page * the number of records on a page. <limit> would be the number of records you would like to display per page.

Categories