Left join does not return ull values - sql

I have two tables:
AppWindowsEvent:
CREATE TABLE [AppWindowsEvent]
(
[idAppWindowEvent] INT IDENTITY(1,1)
, [idAppWindow] INT
, [idEventType] INT
, [Order] INT
, CONSTRAINT PK_idAppWindowEvent PRIMARY KEY ([idAppWindowEvent])
, CONSTRAINT FK_idAppWindowEvent_AppWindow FOREIGN KEY ([idAppWindow]) REFERENCES [AppWindow]([idAppWindow])
, CONSTRAINT FK_idAppWindowEvent_EventType FOREIGN KEY ([idEventType]) REFERENCES [EventType]([idEventType])
)
Event:
CREATE TABLE [Event]
(
[idEvent] [INT] IDENTITY(1,1) NOT NULL
, [idEventType] [INT] NOT NULL
, [idEntity] [INT] NOT NULL
, CONSTRAINT PK_IdEvent PRIMARY KEY([idEvent])
, CONSTRAINT [FK_Event_EventType] FOREIGN KEY([idEventType]) REFERENCES [EventType] ([idEventType])
)
When i run this query:
SELECT
*
FROM
AppWindowsEvent AWE
LEFT JOIN Event E ON AWE.idEventType = E.idEventType
WHERE
AWE.idMill = 1
AND AWE.idAppWindow = 1
ORDER BY
AWE.[Order] ASC
The result: not return nulls.
And when i run this
SELECT
*
FROM
AppWindowsEvent AWE
LEFT JOIN Event E ON AWE.idEventType = E.idEventType
AND E.[idEntity] = 1234
WHERE
AWE.idMill = 1
AND AWE.idAppWindow = 1
ORDER BY
AWE.[Order] ASC
Result: return nulls.
NOTE:
I need the entire set of data that are and are not already configured, in case you want a specific set of events, in the AND of ON can be filtered by specific idEntity of the Event table and the result returns well, but only for that idEntity, in my case I need all idEntity.

Try this
SELECT *
FROM
AppWindowsEvent AWE
LEFT JOIN Event E ON AWE.idEventType = E.idEventType
WHERE
AWE.idMill = 1
AND AWE.idAppWindow = 1
AND E.[idEntity] = 1234
ORDER BY
AWE.[Order] ASC
Or if you doesn't want appear null valor in second table, you can use Inner Join instead Left Join
SELECT *
FROM
AppWindowsEvent AWE
Inner JOIN Event E ON AWE.idEventType = E.idEventType
AND E.[idEntity] = 1234
WHERE
AWE.idMill = 1
AND AWE.idAppWindow = 1
ORDER BY
AWE.[Order] ASC

Related

Ignore records with date range

Trying to build the recurring event system based on Display next event date and the SQL Fiddle
It works well. I tried integrating the leaves plan with the repeating events in the calander to filter it. Mean I need to ignore the repeat events if they fall under the planned leave date.
Here is my leave detail schema
CREATE TABLE dbo.Doctor
(
DoctorID TINYINT IDENTITY(1, 1) NOT NULL,
DoctorName VARCHAR(10) NOT NULL,
CONSTRAINT PK_Doctor_DoctorID PRIMARY KEY (DoctorID)
)
INSERT Doctor(DoctorName) VALUES ('Dr John')
CREATE TABLE dbo.Leaves
( LeaveID INT IDENTITY(1, 1) NOT NULL,
DoctorID TINYINT NOT NULL,
LeaveStartDateTime DATETIME2 NOT NULL,
LeaveEndDateTime DATETIME2 NULL,
CONSTRAINT PK_Leaves_LeaveID PRIMARY KEY (LeaveID),
CONSTRAINT FK_Leaves_DoctorID FOREIGN KEY (DoctorID) REFERENCES dbo.Doctor (DoctorID)
);
Leave Data
From Date '20140115 00:00:00' to '20140116 11:59:59' ->15t & 16th (2 days)
From Date '20140120 00:00:00' to '20140125 11:59:59' -> 20th-25th (6 days)
I need to remove rows which falls between dates mentioned above
The Query
WITH RepeatingEvents AS
( SELECT d.DoctorName,
l.LeaveStartDateTime,
l.LeaveEndDateTime,
e.Name,
re.StartDateTime,
re.EndDateTime,
re.TimesToRepeat,
RepeatEventDate = CAST(c.DateKey AS DATETIME) + CAST(re.StartTime AS DATETIME),
RepeatNumber = ROW_NUMBER() OVER(PARTITION BY re.RepeatEventID ORDER BY c.Datekey)
FROM dbo.Event e
INNER JOIN dbo.RepeatEvent re
ON e.EventID = re.EventID
INNER JOIN dbo.RepeatType rt
ON rt.RepeatTypeID = re.RepeatTypeID
INNER JOIN dbo.Calendar c
ON c.DateKey >= re.StartDate
INNER JOIN dbo.RepeatDayOfWeek rdw
ON rdw.RepeatEventID = re.RepeatEventID
AND rdw.DayNumberOfWeek = c.DayNumberOfWeek
INNER JOIN dbo.DoctorXEvent de ON e.EventID = de.EventID
INNER JOIN dbo.Doctor d ON d.DoctorID = de.DoctorID
LEFT JOIN dbo.Leaves l ON l.DoctorID = d.DoctorID
WHERE rt.Name = 'Weekly'
)
SELECT DoctorName, LeaveStartDateTime, LeaveEndDateTime,Name as EventName, StartDateTime, RepeatEventDate, RepeatNumber
FROM RepeatingEvents
WHERE (TimesToRepeat IS NULL OR RepeatNumber <= TimesToRepeat)
AND (EndDateTime IS NULL OR RepeatEventDate <= EndDateTime)
AND (RepeatEventDate NOT BETWEEN LeaveStartDateTime AND LeaveEndDateTime)
SQL FIDDLE DEMO
My query not filtering those records and also gives duplicate entries because of LEFT JOIN.
The left join to Leaves does not work since the dates are not involved in the join.
Replace the left join with a new predicate to remove unwanted rows:
AND NOT EXISTS
(SELECT 1 FROM Leaves l WHERE l.doctorId = d.doctorId
AND CAST(c.DateKey AS DATETIME) + CAST(re.StartTime AS DATETIME)
BETWEEN l.LeaveStartDateTime AND l.LeaveEndDateTime)
This way the unwanted rows, and the duplicates, are removed.
/Daniel

How to go about this implementation of query

My database table are as follow
CREATE TABLE [dbo].[vProduct](
[nId] [int] NOT NULL, //Primary key
[sName] [varchar](255) NULL
)
CREATE TABLE [dbo].[vProductLanguage](
[kProduct] [int] NOT NULL,
[kLanguage] [int] NOT NULL //Foriegn key to table vLanguage
)
CREATE TABLE [dbo].[vLanguage](
[nId] [int] NOT NULL, //Primary key
[sName] [varchar](50) NULL,
[language] [char](2) NULL
)
Table vProduct has relation to vProductLanguage on vProduct.nId = vProductLanguage.kLanguage
Table vProductLanguage has relation to vLanguage on vProductLanguage.kLanguage = vLanguage.nid
So its like table vProductLanguage will have languages which are being selected
Rows will be like image below
Table vProduct
Table vProductLanguage
Table vLanguage
What i want is select all Languages from table vLanguage and selected languages from table vProductLanguage. This will be associated with table vProduct.
I tried below query but it only returns me the languages which are associated with product.
select * from
vProductLanguage
left join vLanguage on vProductLanguage.kLanguage = vLanguage.nId
left join vProduct on vProductLanguage.kProduct = vProduct.nId
Where vProduct.nId = 1
I want to select all the rows from table vLanguage and table vProductLanguage.
Hope i made my question clear.
It sounds like you want to start your JOIN with the vLanguage table first:
select *
from vLanguage l
left join vProductLanguage pl
on l.nid = pl.kLanguage
left join vProduct p
on pl.kProduct = p.nid
and p.nid = 1
See SQL Fiddle with Demo.
This will return all rows from the vLanguage table and any matching rows from the vProductLanguage table. .
If you have more than one vProduct then you can rewrite the query slightly to:
select *
from vLanguage l
left join
(
select pl.kLanguage,
p.nid,
p.sName
from vProductLanguage pl
left join vProduct p
on pl.kProduct = p.nid
where p.nid = 1
) p
on l.nid = p.kLanguage
See SQL Fiddle with Demo

query optimisation with join on ordered data

My question concerns the optimization of a query sql.
My query retrieves a list of members and their last training.
To get the latest training I do a join on the result of a query returning a complete list of training for all members.
This query works but it is very slow, I'm really interrested if someone would have a solution for it to execute faster.
My query (about 16s):
SELECT
m.nom,
m.prenom,
m.ville,
m.maj,
mbf.libelle,
mbf.datefin,
m.id as idmb
FROM
membres m
LEFT JOIN (
select *
from membreform
where idformation = 1
order by datefin DESC
) as mbf ON mbf.idmembre = m.id
WHERE
role > 0 AND visible = 1
group by m.id
ORDER BY m.maj DESC
limit 0 , 20
My data structure :
membreform (1000 entries)
id int(11) NOT NULL AUTO_INCREMENT,
idmembre int(11) NOT NULL,
libelle varchar(128) NOT NULL,
idformation int(11) NOT NULL,
datedebut date NOT NULL,
datefin date NOT NULL DEFAULT '0000-00-00',
descript text NOT NULL,
KEY id (id),
KEY idmembre (idmembre),
KEY idformation (idformation)
membres (500 entries)
id int(3) NOT NULL AUTO_INCREMENT,
nom varchar(255) NOT NULL,
prenom varchar(255) NOT NULL,
ville varchar(255) NOT NULL,
email varchar(255) NOT NULL,
maj datetime NOT NULL,
role tinyint(4) NOT NULL DEFAULT '1',
PRIMARY KEY (id),
KEY role (role),
KEY maj (maj)
I tested this other way (about 0.40s) but I dont find that really clean
SELECT
m.nom,
m.prenom,
m.ville,
m.maj,
m.id as idmb,
(select
libelle
from
membreform
where
idformation = 1
AND m.id = membreform.idmembre
order by datefin DESC
limit 1
) libelle,
(select
datefin
from
membreform
where
idformation = 1
AND m.id = membreform.idmembre
order by datefin DESC
limit 1
) datefin
FROM
membres m
WHERE
role > 0 AND visible = 1
group by m.id
ORDER BY m.maj DESC
limit 0 , 20
I'm open to any suggestions because I am a bit stuck
thank you
You can use temporary table to increase performace. E.g (MS SQL)
1 Step - Get the memberform data into temp table by adding all relevant where conditions
select *
INTO #TempMembreform
from membreform
where idformation = 1 ...
order by datefin DESC
2 step - do the left outer join as you did in the above first example.
E.g.
SELECT
m.nom,
m.prenom,
m.ville,
m.maj,
mbf.libelle,
mbf.datefin,
m.id as idmb
FROM
membres m
LEFT JOIN #TempMembreForm as mbf
ON mbf.idmembre = m.id
WHERE
role > 0 AND visible = 1
group by m.id
ORDER BY m.maj DESC
limit 0 , 20
3 Step - add NOLOCK keyword if the data is not mision crical (e.g. Bank tracnsactions )
select *
INTO #TempMembreform
from membreform WITH(NOLOCK)
where idformation = 1
order by datefin DESC
SELECT
m.nom,
m.prenom,
m.ville,
m.maj,
mbf.libelle,
mbf.datefin,
m.id as idmb
FROM
membres m with(nolock)
LEFT JOIN #TempMembreForm as mbf
ON mbf.idmembre = m.id
WHERE
role > 0 AND visible = 1
group by m.id
ORDER BY m.maj DESC
limit 0 , 20
My profile

Prevent duplicate rows being inserted

I'm trying to use an SQL insert statement to migrate rows from a table in one database to a table in a different database. The statement works until I add a unique index on the destination table and at that point I'm struggling to get the insert statement to be able to exclude the duplicates. Here's what I though should work:
INSERT INTO [MyDB].[dbo].[HPB] (
[HPID],
[BusinessID]
)
SELECT
PersonId = (SELECT ID FROM [MyDB].[dbo].[HP] WHERE PersonID = lPersonId),
lBusinessId
FROM [MyOriginalDB].[dbo].[tblEmployment]
WHERE
lPersonId in (SELECT PersonID FROM [MyDB].[dbo].[HP])
AND
lBusinessId in (SELECT ID FROM [MyDB].[dbo].[Business])
AND
NOT EXISTS (SELECT * FROM [MyDB].[dbo].[HPB] WHERE
[HPID] = (SELECT ID FROM [MyDB].[dbo].[HP] WHERE PersonID = lPersonId)
AND [BusinessID] = lBusinessId)
The schema for the HPB table is:
CREATE TABLE [dbo].[HPB](
[ID] [int] IDENTITY(1,1) NOT NULL,
[HPID] [int] NOT NULL,
[BusinessID] [int] NOT NULL,
CONSTRAINT [PK_HealthProfessionalBusiness] PRIMARY KEY CLUSTERED)
The unique index is on the [MyDB].[dbo].[HPB] table for columns (HPID, BusinessID)
When I run the insert I get an error about duplicate row inserts and I can't work out why the SQL below doesn't exclude the duplicates.
NOT EXISTS (SELECT * FROM [MyDB].[dbo].[HPB] WHERE
[HPID] = (SELECT ID FROM [MyDB].[dbo].[HP] WHERE PersonID = lPersonId)
AND [BusinessID] = lBusinessId)
Insert MyDB.dbo.HPB( HPID, BusinessID )
Select HP.ID, E.IBusinessID
From [MyOriginalDB].[dbo].[tblEmployment] As E
Join [MyDB].[dbo].[HP] As HP
On HP.PersonId = E.IPersonID
Join [MyDB].[dbo].[Business] As B
On B.ID = E.IBusinessID
Left Join [MyDB].[dbo].[HPB] As HPB
On HPB.BusinessID = E.IBusinessID
And HPB.PersonID = E.IPersonId
Where HPB.ID Is Null
Group By HP.ID, E.IBusinessID
Use:
INSERT INTO [MyDB].[dbo].[HPB]
([HPID], [BusinessID])
SELECT DISTINCT
h.id,
e.lbusinessid
FROM [MyOriginalDB].[dbo].[tblEmployment] e
JOIN [MyDB].[dbo].[HP] h ON h.personid = e.lpersonid
WHERE e.lbusinessid in (SELECT ID FROM [MyDB].[dbo].[Business])
AND NOT EXISTS (SELECT NULL
FROM [MyDB].[dbo].[HPB] hb
WHERE hb.businessid = e.lbusinessid
AND hb.hpid = h.id)

Mysql - help me optimize this query

About the system:
-The system has a total of 8 tables
- Users
- Tutor_Details (Tutors are a type of User,Tutor_Details table is linked to Users)
- learning_packs, (stores packs created by tutors)
- learning_packs_tag_relations, (holds tag relations meant for search)
- tutors_tag_relations and tags and
orders (containing purchase details of tutor's packs),
order_details linked to orders and tutor_details.
For a more clear idea about the tables involved please check the The tables section in the end.
-A tags based search approach is being followed.Tag relations are created when new tutors register and when tutors create packs (this makes tutors and packs searcheable). For details please check the section How tags work in this system? below.
Following is a simpler representation (not the actual) of the more complex query which I am trying to optimize:- I have used statements like explanation of parts in the query
============================================================================
select
SUM(DISTINCT( t.tag LIKE "%Dictatorship%" )) as key_1_total_matches,
SUM(DISTINCT( t.tag LIKE "%democracy%" )) as key_2_total_matches,
td.*, u.*, count(distinct(od.id_od)), `if (lp.id_lp > 0) then some conditional logic on lp fields else 0 as tutor_popularity`
from Tutor_Details AS td JOIN Users as u on u.id_user = td.id_user
LEFT JOIN Learning_Packs_Tag_Relations AS lptagrels ON td.id_tutor = lptagrels.id_tutor
LEFT JOIN Learning_Packs AS lp ON lptagrels.id_lp = lp.id_lp
LEFT JOIN `some other tables on lp.id_lp - let's call learning pack tables set (including
Learning_Packs table)`
LEFT JOIN Order_Details as od on td.id_tutor = od.id_author LEFT JOIN Orders as o on
od.id_order = o.id_order
LEFT JOIN Tutors_Tag_Relations as ttagrels ON td.id_tutor = ttagrels.id_tutor
JOIN Tags as t on (t.id_tag = ttagrels.id_tag) OR (t.id_tag = lptagrels.id_tag)
where `some condition on Users table's fields`
AND CASE WHEN ((t.id_tag = lptagrels.id_tag) AND (lp.id_lp > 0)) THEN `some
conditions on learning pack tables set` ELSE 1 END
AND CASE WHEN ((t.id_tag = wtagrels.id_tag) AND (wc.id_wc > 0)) THEN `some
conditions on webclasses tables set` ELSE 1 END
AND CASE WHEN (od.id_od>0) THEN od.id_author = td.id_tutor and `some conditions on Orders table's fields` ELSE 1 END
AND ( t.tag LIKE "%Dictatorship%" OR t.tag LIKE "%democracy%")
group by td.id_tutor HAVING key_1_total_matches = 1 AND key_2_total_matches = 1
order by tutor_popularity desc, u.surname asc, u.name asc limit
0,20
=====================================================================
What does the above query do?
Does AND logic search on the search keywords (2 in this example - "Democracy" and "Dictatorship").
Returns only those tutors for which both the keywords are present in the union of the two sets - tutors details and details of all the packs created by a tutor.
To make things clear - Suppose a Tutor name "Sandeepan Nath" has created a pack "My first pack", then:-
Searching "Sandeepan Nath" returns Sandeepan Nath.
Searching "Sandeepan first" returns Sandeepan Nath.
Searching "Sandeepan second" does not return Sandeepan Nath.
======================================================================================
The problem
The results returned by the above query are correct (AND logic working as per expectation), but the time taken by the query on heavily loaded databases is like 25 seconds as against normal query timings of the order of 0.005 - 0.0002 seconds, which makes it totally unusable.
It is possible that some of the delay is being caused because all the possible fields have not yet been indexed, but I would appreciate a better query as a solution, optimized as much as possible, displaying the same results
==========================================================================================
How tags work in this system?
When a tutor registers, tags are entered and tag relations are created with respect to tutor's details like name, surname etc.
When a Tutors create packs, again tags are entered and tag relations are created with respect to pack's details like pack name, description etc.
tag relations for tutors stored in tutors_tag_relations and those for packs stored in learning_packs_tag_relations. All individual tags are stored in tags table.
====================================================================
The tables
Most of the following tables contain many other fields which I have omitted here.
CREATE TABLE IF NOT EXISTS `users` (
`id_user` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL DEFAULT '',
`surname` varchar(155) NOT NULL DEFAULT '',
PRIMARY KEY (`id_user`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=636 ;
CREATE TABLE IF NOT EXISTS `tutor_details` (
`id_tutor` int(10) NOT NULL AUTO_INCREMENT,
`id_user` int(10) NOT NULL DEFAULT '0',
PRIMARY KEY (`id_tutor`),
KEY `Users_FKIndex1` (`id_user`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=51 ;
CREATE TABLE IF NOT EXISTS `orders` (
`id_order` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id_order`),
KEY `Orders_FKIndex1` (`id_user`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=275 ;
ALTER TABLE `orders`
ADD CONSTRAINT `Orders_ibfk_1` FOREIGN KEY (`id_user`) REFERENCES `users`
(`id_user`) ON DELETE NO ACTION ON UPDATE NO ACTION;
CREATE TABLE IF NOT EXISTS `order_details` (
`id_od` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_order` int(10) unsigned NOT NULL DEFAULT '0',
`id_author` int(10) NOT NULL DEFAULT '0',
PRIMARY KEY (`id_od`),
KEY `Order_Details_FKIndex1` (`id_order`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=284 ;
ALTER TABLE `order_details`
ADD CONSTRAINT `Order_Details_ibfk_1` FOREIGN KEY (`id_order`) REFERENCES `orders`
(`id_order`) ON DELETE NO ACTION ON UPDATE NO ACTION;
CREATE TABLE IF NOT EXISTS `learning_packs` (
`id_lp` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_author` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id_lp`),
KEY `Learning_Packs_FKIndex2` (`id_author`),
KEY `id_lp` (`id_lp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=23 ;
CREATE TABLE IF NOT EXISTS `tags` (
`id_tag` int(10) unsigned NOT NULL AUTO_INCREMENT,
`tag` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id_tag`),
UNIQUE KEY `tag` (`tag`),
KEY `id_tag` (`id_tag`),
KEY `tag_2` (`tag`),
KEY `tag_3` (`tag`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3419 ;
CREATE TABLE IF NOT EXISTS `tutors_tag_relations` (
`id_tag` int(10) unsigned NOT NULL DEFAULT '0',
`id_tutor` int(10) DEFAULT NULL,
KEY `Tutors_Tag_Relations` (`id_tag`),
KEY `id_tutor` (`id_tutor`),
KEY `id_tag` (`id_tag`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `tutors_tag_relations`
ADD CONSTRAINT `Tutors_Tag_Relations_ibfk_1` FOREIGN KEY (`id_tag`) REFERENCES
`tags` (`id_tag`) ON DELETE NO ACTION ON UPDATE NO ACTION;
CREATE TABLE IF NOT EXISTS `learning_packs_tag_relations` (
`id_tag` int(10) unsigned NOT NULL DEFAULT '0',
`id_tutor` int(10) DEFAULT NULL,
`id_lp` int(10) unsigned DEFAULT NULL,
KEY `Learning_Packs_Tag_Relations_FKIndex1` (`id_tag`),
KEY `id_lp` (`id_lp`),
KEY `id_tag` (`id_tag`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `learning_packs_tag_relations`
ADD CONSTRAINT `Learning_Packs_Tag_Relations_ibfk_1` FOREIGN KEY (`id_tag`)
REFERENCES `tags` (`id_tag`) ON DELETE NO ACTION ON UPDATE NO ACTION;
===================================================================================
Following is the exact query (this includes classes also - tutors can create classes and search terms are matched with classes created by tutors):-
SELECT SUM(DISTINCT( t.tag LIKE "%Dictatorship%" )) AS key_1_total_matches,
SUM(DISTINCT( t.tag LIKE "%democracy%" )) AS key_2_total_matches,
COUNT(DISTINCT( od.id_od )) AS tutor_popularity,
CASE
WHEN ( IF(( wc.id_wc > 0 ), ( wc.wc_api_status = 1
AND wc.wc_type = 0
AND wc.class_date > '2010-06-01 22:00:56'
AND wccp.status = 1
AND ( wccp.country_code = 'IE'
OR wccp.country_code IN ( 'INT' )
) ), 0)
) THEN 1
ELSE 0
END AS 'classes_published',
CASE
WHEN ( IF(( lp.id_lp > 0 ), ( lp.id_status = 1
AND lp.published = 1
AND lpcp.status = 1
AND ( lpcp.country_code = 'IE'
OR lpcp.country_code IN ( 'INT' )
) ), 0)
) THEN 1
ELSE 0
END AS 'packs_published',
td . *,
u . *
FROM tutor_details AS td
JOIN users AS u
ON u.id_user = td.id_user
LEFT JOIN learning_packs_tag_relations AS lptagrels
ON td.id_tutor = lptagrels.id_tutor
LEFT JOIN learning_packs AS lp
ON lptagrels.id_lp = lp.id_lp
LEFT JOIN learning_packs_categories AS lpc
ON lpc.id_lp_cat = lp.id_lp_cat
LEFT JOIN learning_packs_categories AS lpcp
ON lpcp.id_lp_cat = lpc.id_parent
LEFT JOIN learning_pack_content AS lpct
ON ( lp.id_lp = lpct.id_lp )
LEFT JOIN webclasses_tag_relations AS wtagrels
ON td.id_tutor = wtagrels.id_tutor
LEFT JOIN webclasses AS wc
ON wtagrels.id_wc = wc.id_wc
LEFT JOIN learning_packs_categories AS wcc
ON wcc.id_lp_cat = wc.id_wp_cat
LEFT JOIN learning_packs_categories AS wccp
ON wccp.id_lp_cat = wcc.id_parent
LEFT JOIN order_details AS od
ON td.id_tutor = od.id_author
LEFT JOIN orders AS o
ON od.id_order = o.id_order
LEFT JOIN tutors_tag_relations AS ttagrels
ON td.id_tutor = ttagrels.id_tutor
JOIN tags AS t
ON ( t.id_tag = ttagrels.id_tag )
OR ( t.id_tag = lptagrels.id_tag )
OR ( t.id_tag = wtagrels.id_tag )
WHERE ( u.country = 'IE'
OR u.country IN ( 'INT' ) )
AND CASE
WHEN ( ( t.id_tag = lptagrels.id_tag )
AND ( lp.id_lp > 0 ) ) THEN lp.id_status = 1
AND lp.published = 1
AND lpcp.status = 1
AND ( lpcp.country_code = 'IE'
OR lpcp.country_code IN (
'INT'
) )
ELSE 1
END
AND CASE
WHEN ( ( t.id_tag = wtagrels.id_tag )
AND ( wc.id_wc > 0 ) ) THEN wc.wc_api_status = 1
AND wc.wc_type = 0
AND
wc.class_date > '2010-06-01 22:00:56'
AND wccp.status = 1
AND ( wccp.country_code = 'IE'
OR wccp.country_code IN (
'INT'
) )
ELSE 1
END
AND CASE
WHEN ( od.id_od > 0 ) THEN od.id_author = td.id_tutor
AND o.order_status = 'paid'
AND CASE
WHEN ( od.id_wc > 0 ) THEN od.can_attend_class = 1
ELSE 1
END
ELSE 1
END
GROUP BY td.id_tutor
HAVING key_1_total_matches = 1
AND key_2_total_matches = 1
ORDER BY tutor_popularity DESC,
u.surname ASC,
u.name ASC
LIMIT 0, 20
Please note - The provided database structure does not show all the fields and tables as in this query
=====================================================================================
The explain query output:-
Please see this screenshot
http://www.test.examvillage.com/Explain_query.jpg
Information on row counts, value distributions, indexes, size of the database, size of memory, disk layout - raid 0, 5, etc - how many users are hitting your database when queries are slow - what other queries are running. All these things factor into performance.
Also a print out of the explain plan output may shed some light on the cause if it's simply a query / index issue. The exact query would be needed as well.
You really should use some better formatting for the query.
Just add at least 4 spaces to the beginning of each row to get this nice code formatting.
SELECT * FROM sometable
INNER JOIN anothertable ON sometable.id = anothertable.sometable_id
Or have a look here: https://stackoverflow.com/editing-help
Could you provide the execution plan from mysql? You need to add "EXPLAIN" to the query and copy the result.
EXPLAIN SELECT * FROM ...complexquery...
will give you some useful hints (execution order, returned rows, available/used indexes)
Your question is, "how can I find tutors that match certain tags?" That's not a hard question, so the query to answer it shouldn't be hard either.
Something like:
SELECT *
FROM tutors
WHERE tags LIKE '%Dictator%' AND tags LIKE '%Democracy%'
That will work, if you modify your design to have a "tags" field in your "tutors" table, in which you put all the tags that apply to that tutor. It will eliminate layers of joins and tables.
Are all those layers of joins and tables providing real functionality, or just more programming headaches? Think about the functionality that your app REALLY needs, and then simplify your database design!!
Answering my own question.
The main problem with this approach was that too many tables were joined in a single query. Some of those tables like Tags (having large number of records - which can in future hold as many as all the English words in the vocabulary) when joined with so many tables cause this multiplication effect which can in no way be countered.
The solution is basically to make sure too many joins are not made in a single query. Breaking one large join query into steps, using the results of the one query (involving joins on some of the tables) for the next join query (involving joins on the other tables) reduces the multiplication effect.
I will try to provide better explanation to this later.