Concatenate two tables by or - mysql

I have these tables
One text has many-many items writer,line
ttext_obj table
test obj
1 text1
2 text2
3 text3
4 text4
text_obj_writers table
text writer
1 2
2 3
2 4
text_obj_line table
text line
1 2
4 3
1 4
So, I want to pick up the rows of text_obj which have at reast one writer or one line.
For now I made code like this .
The text_obj id which has at least one write
SELECT text.id FROM `text_obj` text
inner join text_obj_writers writer
on writer.obj_id = text.id group by text.id
//it returns
1
2
The text_obj id which have at least one line
SELECT text.id FROM `text_obj` text
inner join text_obj_lines line
on line.obj_id = text.id group by text.id
//it returns
1
4
But I want to take or of these
1
2
4
How can I concatenate two tables by or ?

Use exists:
select o.*
from text_obj o
where exists (select 1
from text_obj_writers tow
where tow.obj_id = o.id
) or
exists (select 1
from text_obj_lines tol
where tol.obj_id = o.id
) ;
This is much better than using aggregation, because you do not need to remove duplicates after joining the tables together.

You could use exists:
select o.*
from ttext_obj o
where
exists (select 1 from text_obj_writers writer w where w.obj_id = o.id)
or exists (select 1 from text_obj_lines l where l.obj_id = o.id)

You can do it with UNION which will also remove duplicates:
select obj_id id from test_obj_writers
union
select obj_id id from test_obj_line
I assume that all obj_ids of both tables exist in the table text_obj.

Related

MySQL - select product_id from 2 different tables and group results

situation:
table 1 - #__virtuemart_products
virtuemart_product_id | product_special
PRODUCTS_IDS | 0 or 1
table 2 - #__virtuemart_product_badges
virtuemart_product_id | product_badge
PRODUCTS_IDS | for this situation code 3
I have a default SQL
SELECT p.`virtuemart_product_id`
FROM `#__virtuemart_products` as p
WHERE p.`product_special` = 1;
results is product IDs like 2,3,225,...
I need modify this SQL syntax for select IDs from 2 different tables and return one column.
If I modify syntax like that:
SELECT p.`virtuemart_product_id`, badges_table.`virtuemart_product_id`
FROM `#__virtuemart_products` as p, `#__virtuemart_product_badges` as badges_table
WHERE p.`product_special` = 1 OR badges_table.`badge` = 3
Result is:
virtuemart_product_id | virtuemart_product_id
1 | 123
1 | 321
1 | 231
....
why is first column 1,1,1,...? here must be product_id, no product_special code
I need group this results into one column virtuemart_product_id
What I doing wrong?
I think what you are looking for is UNION of the IDs fetched from two different tables.
SELECT p.`virtuemart_product_id`, badges_table.`virtuemart_product_id`
FROM `#__virtuemart_products` as p, `#__virtuemart_product_badges` as
badges_table
WHERE p.`product_special` = 1 OR badges_table.`badge` = 3
What the above query is doing is, it is performing a join between the two tables with the condition that product_special should be 1 or badge should be 3. Hence, each row from one table will be joined with each row of the other table where the condition will satisfy.
To get IDs from both the tables you can get the results from each table according to condition and then perform a UNION on them. So for example
(SELECT `virtuemart_product_id` FROM `#__virtuemart_products` WHERE
`product_special` = 1)
UNION
(SELECT `virtuemart_product_id` FROM
`#__virtuemart_product_badges` WHERE `badge` = 3)
I hope this helps.

MySQL create a sum number if row exists in table

I have a statement like so:
select * from category a
inner join category b on a.row=b.relatedRow
inner join category c on b.row=c.relatedRow where a.row=?
I would like to get the number of "levels" like so:
If a has rows, level=1, If b has rows, level=2, If c has rows, level=3.
How can I do this?
Example
row, relatedRow
1,null
2,1
3,2
4,3
5,2
6,5
So, 1 is not related to any row, 2 is related to 1, 3 is related to 2 and so on...
If row=1, level 1 exists since 1 exists
level 2 exists since 2 is related to 1
level 3 exists since 3 and 5 is related to 2
level 4 exists since 6 is related to 5 and 4 is related to 3
Therefore the this tree goes down 4 levels.
try with something along the lines:
select
sum(case when not b.relatedRow is null then 1 else 0 end) as level1_total
sum(case when not c.relatedRow is null then 1 else 0 end) as level2_total
from category a
left join category b on a.row=b.relatedRow
left join category c on b.row=c.relatedRow where a.row=?
of course, you can modify the conditions in the case to suit your definition of has rows
select
max(
case
when c.relatedRow is not null then 3
when b.relatedRow is not null then 2
else 1
end
) as "levels"
from
A a
left outer join B b on b.relatedRow = a.row
left outer join C on c.relatedRow = b.row
Now seeing the edit to the question, I hope you see this pattern can be extended to a 4th level and beyond. If you add a where clause to do any filtering make sure that you only add conditions against A or you'll mess up the outer joins.

MYSQL Join tables with no unique id on multiple columns

I have the following tables:
Table Main:
TestNumber PassageNumber QuestionNumber
1 1 1
1 1 2
1 1 3
1 2 1
1 2 2
1 2 3
Table Child:
TestNumber PassageNumber QuestionNumber User SelectedAnswer
1 1 1 X A
1 2 2 X B
I want to show the data in main table that is not in child table based on a test number and user. So the results i am looking for are the following where the rows from main table are the ones NOT in child:
TestNumber PassageNumber QuestionNumber
1 1 2
1 1 3
1 2 1
1 2 3
I have tried the following query and variations with no luck:
SELECT a.passagenumber, a.questionnumber FROM Main a left outer join
Child b on a.testnumber=b.testnumber where b.user = 'X'
and b.testnumber=1 and a.testnumber=1 and b.selectedanswer is not null
I understand if i had a unique id this would be easy to solve but in this case that is not an option. Any help would be much appreciated.
I thin you can use not in
SELECT a.passagenumber, a.questionnumber FROM Main a
where ( a.testnumber, a.passagenumber, a.questionumber)
not in ( select b.testnumber, b.passagenumber, b.questionumber
from Child b where b.user = 'X' )
Can you join the tables on the three fields, using left join and where the child table value is null?
SELECT p.TestNumber
,p.PassageNumber
,p.QuestionNumber
FROM Parent p
LEFT JOIN Child c ON c.TestNumber = p.TestNumber
AND c.PassageNumber = p.PassageNumber
AND c.QuestionNumber = p.QuestionNumber
AND c.[User] = 'X'
WHERE c.TestNumber IS NULL;

sql query has few rows which are duplicate

I want the value for users with the right ref and also users with extra value 1.
I have the following query but its not giving unique rows ,its giving duplicate rows.How do I resolve that ? I really appreciate any help.
basically its repeating values of ref.id if tab2.user=1 which repeats 4,6 row again in the final query I dont want both but only one as ref.id=0 does not exist but I want extra=1.
SELECT * FROM
tab1,tab2
WHERE tab1.ref=tab2.ref
AND tab1.to_users = 1
OR users.extra=1;
Tab1
sno users ref extra
1 1 4 1
2 2 5 0
3 3 0 1
4 1 0 1
5 2 5 0
6 3 0 1
Tab2
ref ad user
4 A 1
5 B 2
6 C 1
After your last comment:
SELECT sno, users, tab1.ref, extra, max(ad) as ad
FROM
tab1,tab2
WHERE tab1.ref=tab2.ref
AND tab1.users = 1
OR tab1.extra=1
group by sno, users, ref, extra;
This will max the ad column (alternatively you can use min - all depends on your requirements)
example: http://sqlfiddle.com/#!2/1837e/25
You will probably need to use join
SELECT * FROM
tab1 LEFT JOIN tab2 ON tab1.ref=tab2.ref
WHERE tab1.users = 1 OR tab1.extra=1;
GROUP BY tab1.users
edit: added group by
GROUP BY users, give below syntax a try
SELECT * FROM
tab1,tab2
WHERE tab1.ref=tab2.ref AND (tab1.users = 1 OR tab1.extra=1)
GROUP BY users;
Its more common to also join tables than they way you write your syntax,
SELECT * FROM
tab1 JOIN tab2 ON tab1.ref=tab2.ref AND (tab1.users = 1 OR tab1.extra=1)
GROUP BY users;
You should use parenthesis to change the priority of And and OR :
SELECT * FROM
tab1,tab2
WHERE tab1.ref=tab2.ref
AND (tab1.to_users = 1
OR users.extra=1);
otherwise it will be run like this :
SELECT * FROM
tab1,tab2
WHERE (tab1.ref=tab2.ref
AND tab1.to_users = 1 )
OR users.extra=1;
UPDFATE:
I thought you were looking for rows with same reference where to_users is one or extra is one. Then as Krzysztof RosiƄski says LEFT JOIN should do the trick but there's no need to use GROUP BY and perhaps you should use DISTINCT something like this :
SELECT DISTINCT * FROM
tab1 LEFT JOIN tab2 ON tab1.ref=tab2.ref
WHERE tab1.users = 1 OR tab1.extra=1;

MySQL query to retrieve data from tables using inner join

These are the two tables Fruit and Fruit_types.There is a m:n relationship between the two tables so we have the third table fruit_type_fruit which has the primary key from the above two tables. The tables look like this
Fruit
ID NAME
1 A
2 B
3 C
Fruit_type
ID LABEL
1 CITRIC
2 DRUPES
3 UNCATALOGUED
Fruit_type_Fruit
Fruit_id Fruit_type
1 1
1 2
1 3
2 1
3 3
Problem Statement: Some fruits even though they have a category(i.e label) get label as Uncatalogued.
For ex:-
A gets the following labels : Citric, drupes and uncatalogued.
B has citric ,
C has Uncatalogued.
Now I need a query to delete all the records which have a suitable label but still have uncatalogued label too.
In the above example
A record which is uncatalogued should be deleted and not
A Citric and Drupes neither
C Uncatalogued.
How about something like this
SQL Fiddle DEMO
DELETE ftf
FROM fruit_type_fruit ftf
WHERE Fruit_type_ID = 3
AND Fruit_ID IN
(
SELECT *
FROM (
SELECT DISTINCT Fruit_ID
FROM fruit_type_fruit f
WHERE f.Fruit_type_ID = 3
) ss
WHERE Fruit_ID IN (
SELECT *
FROM (
SELECT DISTINCT Fruit_ID
FROM fruit_type_fruit f
WHERE f.Fruit_type_ID <> 3
) s)
)