Mysql cross table join - mysql

hi i have 2 mysql table as follow:
items
id item_name user_id
1 test1 1
2 test2 1
3 test3 1
4 test4 1
project
id user_id items
1 1 1,3
2 1 2,4
how can write a join query that can return each items in a project?
project1 =>
item1=>
[id1] =>
[name1] =>
item3=>
[id3] =>
[name3] =>
Thanks.
UPDATE
item tbl
project tbl

First of all don't store strings of delimited values in your db. You're limiting your self with the means to normally maintain and query data. Normalize your data (in this case by introducing project_items table with project_id and item_id columns). It'll pay off big time in a long run.
In the mean time you can use FIND_IN_SET() to join your tables
SELECT p.id project_id, p.user_id, i.id item_id, i.item_name
FROM project p LEFT JOIN items i
ON FIND_IN_SET(i.id, p.items) > 0
AND p.user_id = i.user_id
ORDER BY p.id, i.id
Output:
| PROJECT_ID | USER_ID | ITEM_ID | ITEM_NAME |
----------------------------------------------
| 1 | 1 | 1 | test1 |
| 1 | 1 | 3 | test3 |
| 2 | 1 | 2 | test2 |
| 2 | 1 | 4 | test4 |
Here is SQLFiddle demo
UPDATE: Values of items should not contain spaces. Either remove them or use REPLACE() like this
ON FIND_IN_SET(i.id, REPLACE(p.items, ' ', '')) > 0
Here is SQLFiddle demo

Your approach is not good. You have to create a relational table between items and projects. Including the list of values ​​followed by commas in a record is not a good idea.
You should create an additional table relational called: project_items
and you can use the following sentence to retrieve the items from a project
select project_items.id_project, items.item_name, items.user_id
from project_items
left join items on project_items.id_item = items.id
That's a better approach

Related

How to craft an SQL to create a report that selects all quotes with a certian line item, and to include another item if it is on that quote?

I have two tables: quote and item.
quote table
id | quote_number
---+-------
1 | 100
2 | 200
item table
id | model | quote_id | other_data
---+-------+----------+-----------
1 | ABC | 1 | xxx
2 | DISC | 1 | xxx
3 | ABC | 2 | xxx
4 | DISC | 2 | xxx
3 | XXX | 3 | xxx
4 | DISC | 3 | xxx
3 | ABC | 4 | xxx
I need to create a report to where I select all quotes that must contain the model ABC AND if they do, I also wish to list model DISC belonging to that quote. I want to list all such item lines. How?
In plain English that would be "give me all quotes with model ABC on them that may also have the discount (DISC) associated with it".
Example Report
quote_id | model | other_data
---------+-------+---------+-
1 | ABC | xxx
1 | DISC | xxx
2 | ABC | xxx
2 | DISC | xxx
So far I can only figure out how to pull lines with ABC in them, but I don't know how to pull in the lines with DISC, which have a condition of "must have ABC connected to the same quote".
You could use a subquery, You can use CTE's as well if you are using MySQL 8.0
SELECT it.quote_id, it.model, it.other_data
FROM item it INNER JOIN (
SELECT quote_id
FROM item i WHERE model = 'ABC') as sub_it
ON it.quote_id=sub_it.quote_id
WHERE it.model='ABC' OR it.model='DISC'
ORDER BY it.quote_id DESC;
DB Fiddle
UNION ALL seems like a good approach:
select ia.*
from items ia
where ia.model = 'ABC'
union all
select id.*
from items id
where id.model = 'DISC' and
exists (select 1 from items ia where ia.quote_id = id.quote_id and ia.model = 'ABC')
order by quote_id, model;
This logic can take advantage of indexes on items(model) and items(quote_id, model). The order by would be needed for any solution.
I vote for the sub query approach as the easiest and cleanest way to go. I dislike using OR conditions so I've used an IN List instead.
SELECT
quote_id,
model,
other_data
FROM item
Where quote_id in ( SELECT quote_id FROM item i WHERE model = 'ABC' )
AND model IN ('ABC', 'DISC')
ORDER BY 1,2;
You should consider the JOIN Statements:
SELECT quote_id, model, other_data FROM item i INNER JOIN quote q ON i.id = q.quote_id WHERE model = 'ABC' or model = 'DISC' ORDER BY quote_id DESC;

MySQL Error to selecting data

I have two column one column associated with another...
Table:base_data
id |---name----|-----des
1 | some name1 | The description1
2 | some name2 | The description2
Table: photos
id |---p_id----|-----photo
1 | 1 | img1s.jpg
2 | 1 | img1w.jpg
3 | 2 | img2.jpg
4 | 2 | img14.jpg
5 | 2 | img15.jpg
I want to select all data from table 1(base_data) and one row from associated row from photos: table how can I do that ????
I don't want to select by greatest n per group I want to select all data from the first table and only one row of the second table which matches with the first table row id, just first match not other.
The Result I want...
id |---name----|---des----|---p_id----|---photo----|
1 | some name |the des..1| 1 | img1s.jpg|
2 | some name |the des..2| 2 | img2.jpg|
I suppose you want to associate base_data with the first photo taken, which should be the one with the lowest photos.id. In MySQL, you could write this as follows: Create an intermediate query which gives - for any p_id - the corresponding record with the lowest id. Then, left join base_data with this intermediate query result. Hope there are not to many typos in it :-) :
select b.id, p2.photo
from base_data b left join
(select p.photo, p.p_id, min(id) from photos p group by p.p_id) p2 on b.id = p2.p_id
If you want the alphanumerically lowest photo name, in MySQL you can do this:
select
t1.*,
t2.photo
from
base_data as t1
left join (
select
p_id,
min(photo) as photo
from
photos
group by
p_id
) as t2 on t2.p_id = t1.id;

MySQL Filtering rows from three tables

Let's say i've got this database:
book
| idBook | name |
|--------|----------|
| 1 |Book#1 |
category
| idCateg| category |
|--------|----------|
| 1 |Adventures|
| 2 |Science F.|
book_categ
| id | idBook | idCateg | DATA |
|--------|--------|----------|--------|
| 1 | 1 | 1 | (null) |
| 2 | 1 | 2 | (null) |
I'm trying to select only the books which are in category 1 AND category 2
This is what I've got so far:
SELECT book.* FROM book,book_categ
WHERE book_categ.idCateg = 1 AND book_categ.idCateg = 2
Obviously, this giving 0 results becouse each row has only one idCateg it does work width OR but the results are not what I need. I've also tried to use a join, but I just can't get the results I expect.
Here it's the SQLFiddle of my current project, the data at the begining is just a sample.
SQLFiddle
Any help will be really appreciated.
You could double join with a constraint on the category id:
SELECT a.* FROM book AS a
INNER JOIN book_categ AS b ON a.idBook = b.idBook AND b.idCateg = 1
INNER JOIN book_categ AS c ON a.idBook = c.idBook AND c.idCateg = 2
You could use a subquery:
SELECT a.* FROM book AS a
WHERE
(SELECT COUNT(DISTINCT idCateg) FROM book_categ AS b
WHERE b.idBook = a.idBook AND b.idCateg IN (1,2)) = 2
If you are on MySQL as your fiddle implies, you should prefer the join variant, since most joins are much faster in MySQL than subqueries.
edit
This one should also work:
SELECT a.* FROM book a
INNER JOIN book_categ AS b ON a.idBook = b.idCateg
WHERE b.idCateg IN (5, 6)
GROUP BY idBook
HAVING COUNT(DISTINCT b.idCateg) = 2
and should be faster than the two above, although you have to change the last number according to the number of category ids you are requesting.

MySQL: How to join three tables in one query with an assign table?

I have three tables:
ITEMS
itemid | itemname
1 | Item 1
FEATURES
featureid | featurename
1 | feature1
2 | feature2
3 | feature3
4 | feature4
... | ...
ASSIGN
assignid | itemid | featureid
1 | 1 | 1
1 | 1 | 2
1 | 1 | 3
1 | 1 | 4
I want one query that will give me a result similar to this:
ITEMS
itemid | itemname | featurename1 | featurename2 | etc
1 | Item 1 | feature1 | feature2 | etc
Is there a way to do this without having a second query? I swear I'm just thinking about it in the wrong way? Any ideas?
Note: features could be anything from 0 to 50 different features. Is my database design perhaps wrong?
Link them using your ASSIGN table and then you can use GROUP_CONCAT() to do what you want. Try this:
SELECT
ITEMS.itemid,
ITEMS.itemname,
FEATURES.featureid,
GROUP_CONCAT(FEATURES.featurename) AS FEATURES
FROM ITEMS
JOIN ASSIGN ON ITEMS.itemid = ASSIGN.itemid
JOIN FEATURES ON FEATURES.featureid = ASSIGN.featureid
SQL Fiddle link
Just use your ASSIGN table as a cross reference for ITEMS and FEATURES. So join everything together through the foreign keys in the ASSIGN table like so:
SELECT
ITEMS.itemid
, ITEMS.itemname
, FEATURES.featureid
, FEATURES.featurename
, ASSIGN.assignid
FROM `ITEMS`
JOIN `ASSIGN`
ON ITEMS.itemsid = ASSIGN.itemid
JOIN `FEATURES`
ON FEATURES.featureid = ASSIGN.featureid

How to impose correct ordering in nested query

I have two tables, one of items, and one of users who have flagged the items. Here is an example:
items: flags:
item_id | item_name | owner_id item_id | flagged_by
------------------------------ --------------------
1 | foo | 1 1 | 2
2 | bar | 2 2 | 4
3 | baz | 2 2 | 7
2 | 7
I want to select the information from the item table about all the items that are in the flag table, ordered by the number of flags. So for the above example, my desired output would be
item_id | item_name | owner_id
------------------------------
2 | bar | 2
1 | foo | 1
The query I have right now is select * from items where id in (select item_id from flags group by item_id order by count(*) desc);
I know that the inner query works correctly (returns all the IDs in the correct order) but when I run the overall query, I just get the items in order of item id. How do I fix my query?
You are ordering the subquery only currently, which doesn't have an effect on the order of the outer query. If you join the tables rather than using a subquery, you should be able to apply an order to the whole query:
select i.*
from items i
join flags f on i.item_id = f.item_id
group by i.item_id
order by count(f.item_id) desc
Demo: http://www.sqlfiddle.com/#!2/f141b/2