How to realize with single query "all, except in list"? - mysql

I need to realize logic "All, except in list" with single query to show a widget on all routes, except listed.
I have next query:
SELECT *
FROM widgets w0_
LEFT JOIN widget_route w1_
ON w0_.id = w1_.widget_id
LEFT JOIN routes r2_
ON w1_.route_id = r2_.id
WHERE r2_.id IS NULL OR w1_.id = 3
Where 3 is an ID of current route, that I have dynamically. But I need to except widget from routes, listed in widget_route table
There is table structure:
widgets:
id, name, published
widget_route:
id, widget_id, route_id
routes:
id, name, path
Can anybody help me?

This is how you select all widgets without any entry in widget_route
by inner select:
SELECT
*
FROM widgets w
WHERE w.id NOT IN (SELECT
wr.widget_id
FROM widget_route wr);
by left join:
SELECT
*
FROM widgets w
LEFT JOIN widget_route wr ON wr.widget_id = w.id
WHERE wr.id IS NULL;
This is how you select all widgets not linked to your route with id 3 by widget_route:
by inner select:
SELECT
*
FROM widgets w
WHERE w.id NOT IN (SELECT
wr.widget_id
FROM widget_route wr
WHERE wr.route_id = 3);
by left join:
SELECT
*
FROM widgets w
LEFT JOIN widget_route wr ON wr.widget_id = w.id AND wr.route_id = 3
WHERE wr.id IS NULL;

Related

mysql jamed after add record from other table

i have a issue with mysql
i have 4 tables i created view from : cots total form
SELECT
`Table`.ItemID,
Details.Material,
Material.Categoryid,
Details.`Usage`,
uc.uc * Details.`Usage` /0.95 AS Cost,
((SELECT cost))/0.9 AS NET_Cost,
((SELECT NET_Cost))/0.9 AS SST,
((SELECT SST))/0.85 AS Local_Price
FROM Details
INNER JOIN Material ON Details.Material = Material.Material
LEFT OUTER JOIN Category ON Material.Categoryid = Category.CATEGORYID
INNER JOIN `Table` ON Details.ItemID = `Table`.ItemID
, uc
WHERE (`Table`.REMARK = 'cost')
other view form name is UC
SELECT
ID,
Material,
Material_Name,
Grand_Cost,
uc,
w1,
w2,
w3
FROM uc
it worked fine if i open " uC" view but other view every time i add uc.uc inside first view it jam "uc.uc * Details.Usage /0.95 AS Cost,"
what could be wrong ? any help is highly appreciated
Move the condition into the join:
SELECT
`Table`.ItemID,
Details.Material,
Material.Categoryid,
Details.`Usage`,
uc.uc * Details.`Usage` /0.95 AS Cost,
((SELECT cost))/0.9 AS NET_Cost,
((SELECT NET_Cost))/0.9 AS SST,
((SELECT SST))/0.85 AS Local_Price
FROM Details
INNER JOIN Material ON Details.Material = Material.Material
LEFT OUTER JOIN Category ON Material.Categoryid = Category.CATEGORYID
INNER JOIN `Table` ON Details.ItemID = `Table`.ItemID
AND `Table`.REMARK = 'cost'
, uc
Also, can you replace , uc with a proper join?

error subquery return more than 1 when doing multiple select

I want to do a multiple select in one query with different conditions. but somehow i'm stuck in this problem. any idea?
SELECT
(select io_link_event_names.name from doors left join controller_devices on doors.iid = controller_devices.iid left join events on controller_devices.mac = events.mac left join io_link_event_names on events.iolinkerid = io_link_event_names.extra where events.iolinkerid = "9000;1") AS forced,
(select doors.name FROM doors) AS doorname
ERROR #1242 - Subquery returns more than 1 row
consider this
SELECT d.[forced], doors.name as doorname
from doors
left join (
select controller_devices.iid, io_link_event_names.name as [forced]
from events
inner join controller_devices on controller_devices.mac = events.mac
inner join io_link_event_names on events.iolinkerid = io_link_event_names.extra
where events.iolinkerid = "9000;1"
) as d on d.iid = doors.iid
If you have more than 1 row in table doors, you get this error. If you want too see door name relevant to event selected in first query, use
select io_link_event_names.name,
doors.name doorname
from doors
left join controller_devices
on doors.iid = controller_devices.iid
left join events
on controller_devices.mac = events.mac
left join io_link_event_names
on events.iolinkerid = io_link_event_names.extra
where events.iolinkerid = "9000;1"

SQL Multi table select query

http://i.stack.imgur.com/mbUTI.jpg
I want to Do a multi select in one query where one table has data from many tables.
i have four tables to combine it into a single output.
here is a image of my table.
i want to select all and don't want other data from other table just main table with name of all other tables
have tried following but its not working.
select * from project_content
left Join project_master on project_master.id = project_content.p_id
left Join project_content_menu on project_content_menu.type_id = project_content.p_c_id
left Join project_menu_master on project_menu_master.id = project_content.m_id
select * from project_content
left Join project_master on project_master.id = project_content.p_id
left Join project_content_menu on project_content_menu.type_id = project_content.p_c_id
left Join project_menu_master on project_menu_master.id = project_content.m_id
select distinct(*) from project_content
left OUTER Join project_master on project_master.id = project_content.p_id
left OUTER Join project_content_menu on project_content_menu.type_id = project_content.p_c_id
left OUTER Join project_menu_master on project_menu_master.id = project_content.m_id
select * from project_content ,project_master,project_content_menu,project_menu_master
where project_master.id = project_content.p_id and project_content_menu.type_id = project_content.p_c_id and project_menu_master.id = project_content.m_id
select pc.id as id , pm.name as pname , pmm.name as menuname , pcm.name as contentname , pc.name as name
from
project_content as pc,
project_master as pm,
project_content_menu as pcm,
project_menu_master as pmm
where
pm.id = pc.p_id
and
pcm.type_id = pc.m_id
and
pmm.id = pc.p_c_id
If I undesrtood you correctly, you want the data just from the main table, but with names instead of foreign keys from other tables? If so, then:
SELECT pc.id, pm.name, pcm.name, pmm.name, pc.name, pc.desc, pc.thumb, pc.src, pc.status
FROM project_content AS pc
LEFT JOIN project_master AS pm ON pm.id = pc.p_id
LEFT JOIN project_content_menu AS pcm ON pcm.type_id = pc.p_c_id
LEFT JOIN project_menu_master AS pmm ON pmm.id = pc.m_id
Im not an expert in SQL but you could try using UNION operator. like this:
select names
from table1
where lastname like k%
UNION
select names
from table2
where lastname like k%
This will combine the result from table1 and table2 and display UNIQUE NAMES in the result where the lastname is starting with k. so, if there is a JOHN KRAMER and JOHN KUTCHER then only JOHN will be displayed once.
If you want duplicate entries , too, then use UNION ALL
I'm not sure, that I understood your problem well, but if you need to add all records together, you should use: UNION ALL
Like:
select name from project_content
UNION ALL
select name from project_master
UNION ALL
select name from project_master
UNION ALL
select name from project_menu_master
Just be sure, that you have the same amount of columns in each select with the same type

SQL - Multiple many-to-many relations filtering SELECT

These are my tables:
Cadastros (id, nome)
Convenios (id, nome)
Especialidades (id, nome)
Facilidades (id, nome)
And the join tables:
cadastros_convenios
cadastros_especialidades
cadastros_facilidades
The table I'm querying for: Cadastros
I'm using MySQL.
The system will allow the user to select multiple "Convenios", "Especialidades" and "Facilidades". Think of each of these tables as a different type of "tag". The user will be able to select multiple "tags" of each type.
What I want is to select only the results in Cadastros table that are related with ALL the "tags" from the 3 different tables provided. Please note it's not an "OR" relation. It should only return the row from Cadastros if it has a matching link table row for EVERY "tag" provided.
Here is what I have so far:
SELECT Cadastro.*, Convenio.* FROM Cadastros AS Cadastro
INNER JOIN cadastros_convenios AS CadastrosConvenio ON(Cadastro.id = CadastrosConvenio.cadastro_id)
INNER JOIN Convenios AS Convenio ON (CadastrosConvenio.convenio_id = Convenio.id AND Convenio.id IN(2,3))
INNER JOIN cadastros_especialidades AS CadastrosEspecialidade ON (Cadastro.id = CadastrosEspecialidade.cadastro_id)
INNER JOIN Especialidades AS Especialidade ON(CadastrosEspecialidade.especialidade_id = Especialidade.id AND Especialidade.id IN(1))
INNER JOIN cadastros_facilidades AS CadastrosFacilidade ON (Cadastro.id = CadastrosFacilidade.cadastro_id)
INNER JOIN Facilidades AS Facilidade ON(CadastrosFacilidade.facilidade_id = Facilidade.id AND Facilidade.id IN(1,2))
GROUP BY Cadastro.id
HAVING COUNT(*) = 5;
I'm using the HAVING clause to try to filter the results based on the number of times it shows (meaning the number of times it has been successfully "INNER JOINED"). So in every case, the count should be equal to the number of different filters I added. So if I add 3 different "tags", the count should be 3. If I add 5 different tags, the count should be 5 and so on. It works fine for a single relation (a single pair of inner joins). When I add the other 2 relations it starts to lose control.
EDIT
Here is something that I believe is working (thanks #Tomalak for pointing out the solution with sub-queries):
SELECT Cadastro.*, Convenio.*, Especialidade.*, Facilidade.* FROM Cadastros AS Cadastro
INNER JOIN cadastros_convenios AS CadastrosConvenio ON(Cadastro.id = CadastrosConvenio.cadastro_id)
INNER JOIN Convenios AS Convenio ON (CadastrosConvenio.convenio_id = Convenio.id)
INNER JOIN cadastros_especialidades AS CadastrosEspecialidade ON (Cadastro.id = CadastrosEspecialidade.cadastro_id)
INNER JOIN Especialidades AS Especialidade ON(CadastrosEspecialidade.especialidade_id = Especialidade.id)
INNER JOIN cadastros_facilidades AS CadastrosFacilidade ON (Cadastro.id = CadastrosFacilidade.cadastro_id)
INNER JOIN Facilidades AS Facilidade ON(CadastrosFacilidade.facilidade_id = Facilidade.id)
WHERE
(SELECT COUNT(*) FROM cadastros_convenios WHERE cadastro_id = Cadastro.id AND convenio_id IN(1, 2, 3)) = 3
AND
(SELECT COUNT(*) FROM cadastros_especialidades WHERE cadastro_id = Cadastro.id AND especialidade_id IN(3)) = 1
AND
(SELECT COUNT(*) FROM cadastros_facilidades WHERE cadastro_id = Cadastro.id AND facilidade_id IN(2, 3)) = 2
GROUP BY Cadastro.id
But I'm concerned about performance. It looks like these 3 sub-queries in the WHERE clause are gonna be over-executed...
Another solution
It joins subsequent tables only if the previous joins were a success (if no rows match one of the joins, the next joins are gonna be joining an empty result-set) (thanks #DRapp for this one)
SELECT STRAIGHT_JOIN
Cadastro.*
FROM
( SELECT Qualify1.cadastro_id
from
( SELECT cc1.cadastro_id
FROM cadastros_convenios cc1
WHERE cc1.convenio_id IN (1, 2, 3)
GROUP by cc1.cadastro_id
having COUNT(*) = 3 ) Qualify1
JOIN
( SELECT ce1.cadastro_id
FROM cadastros_especialidades ce1
WHERE ce1.especialidade_id IN( 3 )
GROUP by ce1.cadastro_id
having COUNT(*) = 1 ) Qualify2
ON (Qualify1.cadastro_id = Qualify2.cadastro_id)
JOIN
( SELECT cf1.cadastro_id
FROM cadastros_facilidades cf1
WHERE cf1.facilidade_id IN (2, 3)
GROUP BY cf1.cadastro_id
having COUNT(*) = 2 ) Qualify3
ON (Qualify2.cadastro_id = Qualify3.cadastro_id) ) FullSet
JOIN Cadastros AS Cadastro
ON FullSet.cadastro_id = Cadastro.id
INNER JOIN cadastros_convenios AS CC
ON (Cadastro.id = CC.cadastro_id)
INNER JOIN Convenios AS Convenio
ON (CC.convenio_id = Convenio.id)
INNER JOIN cadastros_especialidades AS CE
ON (Cadastro.id = CE.cadastro_id)
INNER JOIN Especialidades AS Especialidade
ON (CE.especialidade_id = Especialidade.id)
INNER JOIN cadastros_facilidades AS CF
ON (Cadastro.id = CF.cadastro_id)
INNER JOIN Facilidades AS Facilidade
ON (CF.facilidade_id = Facilidade.id)
GROUP BY Cadastro.id
Emphasis mine
"It should only return the row from Cadastros if it has a matching row for EVERY "tag" provided."
"where there is a matching row"-problems are easily solved with EXISTS.
EDIT After some clarification, I see that using EXISTS is not enough. Comparing the actual row counts is necessary:
SELECT
*
FROM
Cadastros c
WHERE
(SELECT COUNT(*) FROM cadastros_facilidades WHERE cadastro_id = c.id AND id IN (2,3)) = 2
AND
(SELECT COUNT(*) FROM cadastros_especialidades WHERE cadastro_id = c.id AND id IN (1)) = 1
AND
(SELECT COUNT(*) FROM cadastros_facilidades WHERE cadastro_id = c.id AND id IN (1,2)) = 2
The indexes on the link tables should be (cadastro_id, id) for this query.
Depending on the size of the tables (records), WHERE-based subqueries, running a test on every row CAN SIGNIFICANTLY hit performance. I have restructured it which MIGHT better help, but only you would be able to confirm. The premise here is to have the first table based on getting distinct IDs that meet the criteria, join THAT set to the next qualifier criteria... joined to the FINAL set. Once that has been determined, use THAT to join to your main table and its subsequent links to get the details you are expecting. You also had an overall group by by the ID which will eliminate all other nested entries as found in the support details table.
All that said, lets take a look at this scenario. Start with the table that would be EXPECTED TO HAVE THE LOWEST RESULT SET to join to the next and next. if cadastros_convenios has IDs that match all the criteria include IDs 1-100, great, we know at MOST, we'll have 100 ids.
Now, these 100 entries are immediately JOINED to the 2nd qualifying criteria... of which, say it only matches ever other... for simplicity, we are now matched on 50 of the 100.
Finally, JOIN to the 3rd qualifier based on the 50 that qualified and you get 30 entries. So, within these 3 queries you are now filtered down to 30 entries with all the qualifying criteria handled up front. NOW, join to the Cadastros and then subsequent tables for the details based ONLY on the 30 that qualified.
Since your original query would eventually TRY EVERY "ID" for the criteria, why not pre-qualify it up front with ONE query and get just those that hit, then move on.
SELECT STRAIGHT_JOIN
Cadastro.*,
Convenio.*,
Especialidade.*,
Facilidade.*
FROM
( SELECT Qualify1.cadastro_id
from
( SELECT cc1.cadastro_id
FROM cadastros_convenios cc1
WHERE cc1.convenio_id IN (1, 2, 3)
GROUP by cc1.cadastro_id
having COUNT(*) = 3 ) Qualify1
JOIN
( SELECT ce1.cadastro_id
FROM cadastros_especialidades ce1
WHERE ce1.especialidade_id IN( 3 )
GROUP by ce1.cadastro_id
having COUNT(*) = 1 ) Qualify2
ON Qualify1.cadastro_id = Qualify2.cadastro_id
JOIN
( SELECT cf1.cadastro_id
FROM cadastros_facilidades cf1
WHERE cf1.facilidade_id IN (2, 3)
GROUP BY cf1.cadastro_id
having COUNT(*) = 2 ) Qualify3
ON Qualify2.cadastro_id = Qualify3.cadastro_id ) FullSet
JOIN Cadastros AS Cadastro
ON FullSet.Cadastro_id = Cadastro.Cadastro_id
INNER JOIN cadastros_convenios AS CC
ON Cadastro.id = CC.cadastro_id
INNER JOIN Convenios AS C
ON CC.convenio_id = C.id
INNER JOIN cadastros_especialidades AS CE
ON Cadastro.id = CE.cadastro_id
INNER JOIN Especialidades AS E
ON CE.especialidade_id = E.id
INNER JOIN cadastros_facilidades AS CF
ON Cadastro.id = CF.cadastro_id
INNER JOIN Facilidades AS F
ON CF.facilidade_id = F.id

Three table query MySQL

I have three tables that have common affiliate_id field:
impressions, clicks, commissions
I want to select all the data from these three tables where the affiliate_id = '$iAid' in one query, then handle the data in php.
How would I write a query like this?
Here's PHP code assuming you're using MYSQL:
$qry = "SELECT im.*, cl.*, co.*
FROM `impressions` im, `clicks` cl, `comissions` co
WHERE im.`affiliate_id`=cl.`affiliate_id`
AND cl.`affiliate_id`=co.`affiliate_id`
AND im.`affiliate_id`='".$iAid."'";
SELECT <YOUR COLUMN LIST>
FROM impressions a, clicks b, commissions c
WHERE a.affiliate_id = '$iAID'
AND a.affiliate_id = b.affiliate_id
AND b.affiliate_id = c.affiliate_id
SELECT * FROM impressions AS i JOIN clicks AS c ON i.affiliate_id = c.affiliate_id JOIN commissions AS m ON i.affiliate_id = m.affiliate_id WHERE i.affiliate_id = '$iAid'
should do the trick
Do a left join in mysql query:
Select * from Impressions imp
Left join clicks c on c.affiliate_id = imp.affiliate_id
Left join commissions com on com.affiliate_id = imp_affiliate_id
Where ***
limit ***
ect....
select * from
impression a
join clicks b on (a.affiliate_id = b.affiliate_id)
join commissions c on (a.affiliate_id = c.affiliate_id)
where a.affiliate_id = ?
How about a join:
select * from impressions, clicks, commissions
where impressions.affiliate_id = clicks.affiliate_id
and clicks.affiliate_id = commissions.affiliate_id
and impressions.affiliate_id = '$iAid'