Improve speed of MySQL Update query with Inner Join and Where - mysql

I have an update query that is running slow and wanted to see if i could improve performance
Here is the query
update appmaster a
INNER JOIN appid b ON a.activity = b.activity
SET a.activity_id = b.activity_id
WHERE a.activity_id IS null
appmaster contains about 9 millions records but less than 1 million of those have activity_id that is null
appid contains 171,000 records
I have an tried setting up an index on activity for both tables but doesn't seem to help.
I would set an index on appmaster activity_id because that is my where condition but that is the value im setting.
Any ideas?
appmaster table
CREATE TABLE appfiltration.appmaster (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(75) DEFAULT NULL,
activity varchar(150) NOT NULL,
class varchar(150) NOT NULL,
device varchar(60) NOT NULL,
version varchar(60) DEFAULT NULL,
theme varchar(50) DEFAULT NULL,
upload_date date DEFAULT NULL,
activity_id int(11) DEFAULT NULL,
PRIMARY KEY (id),
INDEX idx_activity (activity)
)
ENGINE = INNODB
AUTO_INCREMENT = 9457807
AVG_ROW_LENGTH = 136
CHARACTER SET utf8
COLLATE utf8_unicode_ci;
appid table
CREATE TABLE appfiltration.appid (
activity_id int(11) NOT NULL AUTO_INCREMENT,
activity varchar(200) NOT NULL,
name varchar(50) DEFAULT NULL,
result int(11) NOT NULL DEFAULT 0,
change1 float DEFAULT NULL,
result_last int(11) NOT NULL DEFAULT 0,
change2 float DEFAULT NULL,
result_last2 int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (activity_id, activity)
)
ENGINE = INNODB
AUTO_INCREMENT = 251064
AVG_ROW_LENGTH = 63
CHARACTER SET utf8
COLLATE utf8_unicode_ci;
results from
EXPLAIN SELECT a.activity_id, b.activity_id
FROM appmaster a
JOIN appid b ON a.activity = b.activity
WHERE a.activity_id IS NULL

Related

Optimizing MySQL "IN" Select?

I have the following MySQL query:
SELECT
`influencers`.*,
`locations`.`country_name`
FROM
`influencers`
LEFT JOIN `locations` ON `influencers`.`country_id` = `locations`.`id`
WHERE
`is_dead` = 0
AND `influencers`.`is_private` = 0
AND `influencers`.`country_id` = '31'
AND influencers.uuid IN(
SELECT
`influencer_uuid` FROM `category_influencer`
WHERE
`category_influencer`.`category_id` = 17
AND `category_influencer`.`is_main` = 1)
ORDER BY
`influencers`.`followed_by` DESC
LIMIT 7 OFFSET 6
I have identified the IN subquery is causing a lag of around 10s for this query to complete. Here is the EXPLAIN:
I have indexes on all columns being queried.
How can I significantly speed this query up?
Updated with SHOW CREATE TABLE for both:
locations
CREATE TABLE `locations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`country_name` varchar(255) DEFAULT NULL,
`city_name` varchar(255) DEFAULT NULL,
`type` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_index` (`city_name`, `country_name`),
KEY `type` (`type`)
USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 6479 DEFAULT CHARSET = utf8mb4
influencers
CREATE TABLE `influencers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`bio` varchar(255) CHARACTER
SET utf8mb4 DEFAULT NULL,
`url` varchar(255) CHARACTER
SET utf8mb4 DEFAULT NULL,
`followed_by` int(11) DEFAULT NULL,
`follows` int(11) DEFAULT NULL,
`full_name` varchar(255) CHARACTER
SET utf8mb4 NOT NULL,
`social_id` varchar(255) DEFAULT NULL,
`is_private` tinyint (1) DEFAULT NULL,
`avatar` varchar(255) NOT NULL,
`username` varchar(30) NOT NULL,
`text_search` text CHARACTER
SET utf8mb4 NOT NULL,
`updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`uuid` varchar(255) DEFAULT NULL,
`is_dead` tinyint (4) DEFAULT NULL,
`country_id` int(11) DEFAULT NULL,
`city_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `uuid` (`uuid`),
KEY `is_dead` (`is_dead`),
KEY `updated_at` (`updated_at`),
KEY `followed_by` (`followed_by`),
KEY `social_id` (`social_id`),
KEY `is_private` (`is_private`),
KEY `country_id` (`country_id`),
FULLTEXT KEY `text_search` (`text_search`)) ENGINE = InnoDB AUTO_INCREMENT = 2278376 DEFAULT CHARSET = utf8
You could avoid the in clause using an inner join
SELECT
`influencers`.*,
`locations`.`country_name`
FROM
`influencers`
INNER JOIN (
SELECT
`influencer_uuid` FROM `category_influencer`
WHERE
`category_id` = 17
AND `is_main` = 1
) T ON T.influencer_uuid = influencers.uuid
LEFT JOIN `locations` ON `influencers`.`country_id` = `locations`.`id`
WHERE
`is_dead` = 0
AND `is_private` = 0
AND `country_id` = '31'
ORDER BY
`followed_by` DESC
LIMIT 7 OFFSET 6
This way instead of an iteration on all the IN result you use just a single relational match based on join
Unless I missed something, you can replace the subselect with JOIN:
SELECT influencers.*,
locations.country_name
FROM influencers
JOIN category_influencer T ON (
T.influencer_uuid = influencers.uuid
AND category_id = 17
AND is_main = 1)
LEFT JOIN locations ON influencers.country_id = locations.id
WHERE is_dead = 0
AND is_private = 0
AND country_id = '31'
ORDER BY followed_by DESC
LIMIT 7 OFFSET 6

inner joining on a update

I am trying to check if the user owns a course, I am trying to do this by getting the transaction_id (someone who's applied to a course) and then left join the courses and check the course_user against a session where the transaction_course is equal to course id
My SQL
UPDATE training_transactions
LEFT JOIN training
ON training_transactions.training_transaction_id =
training.course_id
SET training_transactions.training_transaction_status = 'declined'
WHERE training_transactions.training_transaction_id = ?
AND training.course_user = ?
training_transaction:
CREATE TABLE IF NOT EXISTS `training_transactions` (
`training_transaction_id` int(11) NOT NULL,
`training_transaction_user` int(11) NOT NULL,
`training_transaction_course` int(11) NOT NULL,
`training_transaction_status` varchar(50) NOT NULL,
`training_transaction_enabled` varchar(50) NOT NULL DEFAULT 'enabled',
`training_transaction_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
training
CREATE TABLE IF NOT EXISTS `training` (
`course_id` int(11) NOT NULL,
`course_user` int(11) NOT NULL,
`course_type` varchar(255) NOT NULL,
`course_name` varchar(255) NOT NULL,
`course_location` varchar(255) NOT NULL,
`course_duration` varchar(255) NOT NULL,
`course_fitness_type` varchar(255) NOT NULL,
`course_instructor_name` varchar(255) NOT NULL,
`course_price` int(15) NOT NULL,
`course_start_date` date NOT NULL,
`course_max_attendees` int(8) NOT NULL,
`course_accommodation` varchar(255) NOT NULL,
`course_accommodation_price` varchar(255) NOT NULL,
`course_status` varchar(50) NOT NULL,
`course_enabled` varchar(10) NOT NULL DEFAULT 'enabled'
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=latin1;
So my question, how can I update if the transaction id matches the course_id and the user's session (below) matches the course_user?
Session::get('id') // user id
You should be testing training_transaction_course in the WHEN clause, not training_transaction_id. And you should use INNER JOIN, not LEFT JOIN; you only need LEFT JOIN if you need to get rows in the first table that have no matches in the second table.
UPDATE training_transactions AS tt
INNER JOIN training AS t ON tt.training_transaction_id = t.course_id
SET tt.training_transaction_status = 'declined'
WHERE tt.training_transaction_course = ?
AND t.course_user = ?

Mysql Cluster stored procedure with subselect group by and order by is slow

i have migrated this stored procedure from ms sql server 2012 to mysql cluster.
CREATE DEFINER = 'root'#'%'
PROCEDURE get_activeSub(IN p_top int, IN p_carrierid int, IN p_mode int)
BEGIN
DECLARE v_tomorrow datetime;
DECLARE v_temp int;
DECLARE v_sysdate datetime;
SET v_tomorrow = DATE_ADD(CURRENT_DATE(), INTERVAL 1 DAY);
IF (p_mode IS NULL) THEN
SET p_mode = 0;
END IF;
IF ((p_mode != 0) AND (p_mode != 1)) THEN
SET p_mode = 0;
END IF;
IF (p_mode = 0) THEN
SET v_sysdate = SYSDATE();
SELECT
activeSub.*
FROM
(
SELECT
-- e.msisdn
-- ,e.hasCredit
-- ,e.lastBillingDate
-- ,
MIN(a.schedulingId) AS schedulingIdMin
FROM
activeSub a
LEFT OUTER JOIN endUser e /*force INDEX for ORDER BY (IDX_enduser_lastBillingDate)*/ ON e.endUserId = a.endUserId
INNER JOIN smartBillingInterval sb ON a.serviceId = sb.serviceId AND sb.transactionTypeId = 7
WHERE
(a.stateId IN (2000, 2007, 2008) OR a.stateid IS NULL)
AND a.nextBillingDate < v_tomorrow
AND a.carrierId = p_carrierId
AND (a.numRetry IS NULL OR a.numRetry <= sb.maxRetry_full)
AND (a.lastBillingPrice IS NULL OR (a.lastBillingPrice = sb.price_full AND a.nextBillingDate < v_sysdate))
GROUP BY
e.enduserid
-- ,e.hasCredit
-- ,e.lastBillingDate
ORDER BY
e.hasCredit DESC
,e.lastBillingDate DESC
LIMIT p_top
) aGrouped INNER JOIN activeSub ON activeSub.schedulingId = aGrouped.schedulingIdMin
ORDER BY activeSub.numRetry;
ELSE
SELECT
COUNT(*)
FROM (SELECT
COUNT(*) AS QUANTITY
FROM activeSub a
left outer join endUser e
ON e.endUserId = a.endUserId
INNER JOIN smartBillingInterval sb
ON a.serviceId = sb.serviceId AND sb.transactionTypeId = 7
-- where stateId not in (71010,21010) and nextBillingDate<#tomorrow and a.carrierId=#carrierId
WHERE (stateId IN (2000, 2007, 2008) OR stateid IS NULL)
AND nextBillingDate < v_tomorrow
AND a.carrierId = p_carrierId
-- NUMRETRY IN INTERVALS
AND (numRetry IS NULL OR numRetry <= sb.maxRetry_full)
-- NEXT PRICE TO USE, TAKING CARE ABOUT SHORT-RETRIES FOR FULL PRICES SWEPT
AND (lastBillingPrice IS NULL OR (lastBillingPrice = sb.price_full AND nextBillingDate < SYSDATE()))
GROUP BY e.msisdn,
e.hasCredit,
e.lastBillingDate) AS Q;
END IF;
END
i call them with call get_activesub(300,101101,0)
the structure of tables involved are
USE lisabel;
CREATE TABLE lisabel.activesub (
endUserId bigint(20) NOT NULL,
serviceId int(11) NOT NULL,
carrierId int(11) NOT NULL,
shortCodeId int(11) DEFAULT NULL,
schedulingId bigint(20) NOT NULL,
pendingDate datetime DEFAULT NULL,
subscriptionDate datetime DEFAULT NULL,
firstBillingDate datetime DEFAULT NULL,
numBilling int(11) DEFAULT NULL,
numCredits int(11) DEFAULT NULL,
originId int(11) NOT NULL,
text varchar(160) DEFAULT NULL,
hierarchyId int(11) DEFAULT NULL,
subscriptionHierarchyId int(11) NOT NULL,
contentId bigint(20) DEFAULT NULL,
moId bigint(20) DEFAULT NULL,
channel varchar(100) DEFAULT NULL,
pinCode varchar(4) DEFAULT NULL,
transactionId bigint(20) DEFAULT NULL,
nextBillingDate datetime DEFAULT NULL,
deliveryReportId int(11) DEFAULT NULL,
retCode varchar(255) DEFAULT NULL,
numRetry int(11) DEFAULT NULL,
numShortRetry int(11) DEFAULT NULL,
stateId int(11) DEFAULT NULL,
previousStateId int(11) DEFAULT NULL,
page varchar(100) DEFAULT NULL,
handsetId int(11) DEFAULT NULL,
lastBillingDate datetime DEFAULT NULL,
banningCount int(11) DEFAULT NULL,
flowId int(11) DEFAULT NULL,
subscriptionNumRetry int(11) DEFAULT NULL,
subscriptionNumShortRetry int(11) DEFAULT NULL,
debit int(11) DEFAULT NULL,
partnerNotificationMask varchar(10) DEFAULT NULL,
lastBillingPrice decimal(10, 2) DEFAULT NULL,
sessionId bigint(20) DEFAULT NULL,
gclid varchar(50) DEFAULT NULL,
msisdn varchar(50) DEFAULT NULL,
PRIMARY KEY (endUserId, serviceId),
INDEX FK_activeSub_content USING BTREE (contentId),
INDEX FK_activeSub_deliveryReport USING BTREE (deliveryReportId),
INDEX FK_activeSub_handset USING BTREE (handsetId),enter code here
INDEX FK_activeSub_hierachy USING BTREE (hierarchyId),
INDEX FK_activeSub_origin USING BTREE (originId),
INDEX FK_activeSub_shortCode USING BTREE (shortCodeId),
INDEX FK_activeSub_subscriptionHierarchy USING BTREE (subscriptionHierarchyId),
INDEX IDX_activesub_carrierId USING BTREE (carrierId),
INDEX IDX_activesub_endUserId USING BTREE (endUserId),
INDEX IDX_activesub_lastBillingPrice USING BTREE (lastBillingPrice),
INDEX IDX_activesub_nextBillingDate USING BTREE (nextBillingDate),
INDEX IDX_activesub_numRetry USING BTREE (numRetry),
INDEX IDX_activesub_schedulingId USING BTREE (schedulingId),
INDEX IDX_activesub_serviceId USING BTREE (serviceId),
INDEX IDX_activesub_stateId USING BTREE (stateId)
)
ENGINE = NDBCLUSTER
AVG_ROW_LENGTH = 204
CHARACTER SET latin1
COLLATE latin1_swedish_ci;
USE lisabel;
CREATE TABLE lisabel.enduser (
endUserId bigint(20) NOT NULL AUTO_INCREMENT,
msisdn varchar(50) NOT NULL,
carrierId int(11) NOT NULL,
handsetId int(11) DEFAULT NULL,
hasCredit bit(1) DEFAULT NULL,
lastBillingDate datetime DEFAULT NULL,
lastAttemptDate datetime DEFAULT NULL,
PRIMARY KEY (endUserId),
INDEX FK_endUser_handset USING BTREE (handsetId),
INDEX FK_endUsers_carrier USING BTREE (carrierId),
INDEX IDX_enduser_endUserId USING BTREE (endUserId),
INDEX IDX_enduser_lastBillingDate USING BTREE (lastBillingDate),
UNIQUE INDEX IDX_enduser_msisdn USING BTREE (msisdn)
)
ENGINE = NDBCLUSTER
AUTO_INCREMENT = 2040353
AVG_ROW_LENGTH = 60
CHARACTER SET latin1
COLLATE latin1_swedish_ci;
both tables are table in memory.
table activesub have 300.000 records the enduser table have 2.000.000 records.
if i run explain extended
EXPLAIN EXTENDED
SELECT
activeSub.*
FROM
(`enter code here`
SELECT
-- e.msisdn
-- ,e.hasCredit
-- ,e.lastBillingDate
-- ,
MIN(a.schedulingId) AS schedulingIdMin
FROM
activeSub a
LEFT OUTER JOIN endUser e USE INDEX for ORDER BY (IDX_enduser_lastBillingDate) ON e.endUserId = a.endUserId
INNER JOIN smartBillingInterval sb ON a.serviceId = sb.serviceId AND sb.transactionTypeId = 7
WHERE
(a.stateId IN (2000, 2007, 2008) OR a.stateid IS NULL)
AND a.nextBillingDate < '2014-12-15'
AND a.carrierId = 101101
AND (a.numRetry IS NULL OR a.numRetry <= sb.maxRetry_full)
AND (a.lastBillingPrice IS NULL OR (a.lastBillingPrice = sb.price_full AND a.nextBillingDate < sysdate()))
GROUP BY
e.enduserid
-- ,e.hasCredit
-- ,e.lastBillingDate
ORDER BY
e.hasCredit DESC
,e.lastBillingDate DESC
LIMIT 300
) aGrouped INNER JOIN activeSub ON activeSub.schedulingId = aGrouped.schedulingIdMin
ORDER BY activeSub.numRetry;
SHOW WARNINGS;
The result is:
1 PRIMARY <derived2> ALL (null) (null) (null) (null) 300 100 Using where; Using temporary; Using filesort
1 PRIMARY activeSub ref IDX_activesub_schedulingId IDX_activesub_schedulingId 8 aGrouped.schedulingIdMin 1 100 (null)
2 DERIVED a ref IDX_activesub_stateId,IDX_activesub_lastBillingPrice,IDX_activesub_numRetry,IDX_activesub_nextBillingDate,IDX_activesub_carrierId,IDX_activesub_serviceId IDX_activesub_carrierId 4 const 305303 100 Parent of 3 pushed join#1; Using where with pushed condition (((`lisabel`.`a`.`stateId` in (2000,2007,2008)) or isnull(`lisabel`.`a`.`stateId`)) and (`lisabel`.`a`.`nextBillingDate` < '2014-12-15')); Using temporary; Using filesort
2 DERIVED sb eq_ref PRIMARY PRIMARY 8 lisabel.a.serviceId,const 1 100 Child of 'a' in pushed join#1; Using where
2 DERIVED e eq_ref PRIMARY,IDX_enduser_endUserId PRIMARY 8 lisabel.a.endUserId 1 100 Child of 'a' in pushed join#1; Using where
And the workbench execution plan is:
The execution time is 2.5 - 3 seconds. How you can improve the execution time?

my join returns 0 results

I have to following 3 tables: room, reservation and reservationroom
Their structure is as follows:
CREATE TABLE `room` (
`roomID` int(11) NOT NULL AUTO_INCREMENT,
`hotelID` int(11) NOT NULL,
`roomtypeID` int(11) NOT NULL,
`roomNumber` int(11) NOT NULL,
`roomName` varchar(255) NOT NULL,
`roomName_en` varchar(255) NOT NULL,
`roomDescription` text,
`roomDescription_en` text,
`roomSorder` int(11) NOT NULL,
`roomVisible` tinyint(4) NOT NULL,
PRIMARY KEY (`roomID`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8;
CREATE TABLE `reservation` (
`reservationID` int(11) NOT NULL AUTO_INCREMENT,
`customerID` int(11) NOT NULL,
`hotelID` int(11) NOT NULL,
`reservationCreatedOn` datetime NOT NULL,
`reservationCreatedFromIp` varchar(255) CHARACTER SET greek NOT NULL,
`reservationNumberOfAdults` tinyint(4) NOT NULL,
`reservationNumberOfChildrens` tinyint(4) NOT NULL,
`reservationArrivalDate` date NOT NULL,
`reservationDepartureDate` date NOT NULL,
`reservationCustomerComment` text CHARACTER SET greek,
PRIMARY KEY (`reservationID`)
) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=utf8;
CREATE TABLE `reservationroom` (
`reservationroomID` int(11) NOT NULL AUTO_INCREMENT,
`reservationID` int(11) NOT NULL,
`hotelID` int(11) NOT NULL,
`roomID` int(11) NOT NULL,
PRIMARY KEY (`reservationroomID`)
) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=utf8;
(please note that foreign keys have been removed from create statements for sake of simplicity)
What I am trying to do: I want to get all rooms that are not reserved for specific dates, that is only the free rooms from the specific hotel (I have its ID)
Here is the query that I have right now:
SELECT r.* FROM room r
LEFT JOIN `reservationroom` rr
ON r.`hotelID` = rr.`hotelID`
AND r.`roomID` = rr.`roomID`
LEFT JOIN `reservation` re
ON rr.`reservationID` = re.`reservationID`
WHERE (rr.`reservationroomID` = ''
OR rr.`reservationroomID` IS NULL
AND re.`reservationArrivalDate` >= 2014-08-27
AND re.`reservationDepartureDate` <= 2014-08-29
AND r.`hotelID` = 10
AND r.`roomVisible` = 1);
This query now returns 0 results. It should return 9 records, since the hotel with ID = 10 has 9 rooms that are free (no resevations for specific dates exist in the reservation table)
Can anyone give me a hand with this please? I am trying to sort this out couple of hours, without any success.
You are using left join, so conditions on all but the first table should be in the on clauses. I think you want a query more like this:
SELECT r.*
FROM room r LEFT JOIN
`reservationroom` rr
ON r.`hotelID` = rr.`hotelID` AND
r.`roomID` = rr.`roomID` LEFT JOIN
`reservation` re
ON rr.`reservationID` = re.`reservationID` AND
re.`reservationArrivalDate` >= 2014-08-27 AND
re.`reservationDepartureDate` <= 2014-08-29
WHERE r.`hotelID` = 10 AND r.`roomVisible` = 1 AND re.reservationID is null;
I'm not sure what the comparison is to the empty string. It doesn't seem necessary for this purpose.

getting number of records from 2 tables - one to many relationship

I have problem with search query that i have to built on the fly to return records from the database.
I have 2 tables: adds andadds_filters`. For the sake of simplicity, i make the table adds shorter than it is, removing some of the (irrelevant) fields
My table structure:
CREATE TABLE IF NOT EXISTS `adds` (
`addid` int(11) NOT NULL AUTO_INCREMENT,
`memberid` int(11) NOT NULL,
`isnew` int(11) NOT NULL,
`catid` int(11) NOT NULL,
`manufacturerid` int(11) NOT NULL,
`modelid` varchar(255) DEFAULT NULL,
`colorid` int(11) DEFAULT NULL,
`geographicareaid` int(45) NOT NULL,
`addtypeid` varchar(45) NOT NULL,
`addcreatedon` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`addvalidfrom` date NOT NULL,
`addvaliduntil` date NOT NULL,
`addcreatedfromip` varchar(255) NOT NULL,
`yearofmanufacturing` varchar(255) DEFAULT NULL,
`monthofmanufacturing` int(11) DEFAULT NULL,
`hoursused` int(11) DEFAULT NULL,
`cc2` int(11) DEFAULT NULL,
`horsepowers` int(11) DEFAULT NULL,
`metalic` tinyint(4) DEFAULT NULL,
`isdamaged` tinyint(4) DEFAULT NULL,
`price` float DEFAULT NULL,
`hasvat` tinyint(4) NOT NULL,
`canbenegotiated` tinyint(4) DEFAULT NULL,
`addtitle` varchar(255) DEFAULT NULL,
`addtext` text NOT NULL,
`youtubevideo` varchar(255) DEFAULT NULL,
`visible` tinyint(4) DEFAULT NULL,
`ff1` varchar(255) DEFAULT NULL,
`ff2` varchar(255) DEFAULT NULL,
`ff3` varchar(255) DEFAULT NULL,
`ff4` varchar(255) DEFAULT NULL,
PRIMARY KEY (`addid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=43 ;
CREATE TABLE IF NOT EXISTS `adds_filters` (
`addfilterid` int(11) NOT NULL AUTO_INCREMENT,
`addid` int(11) NOT NULL,
`filterid` int(11) NOT NULL,
PRIMARY KEY (`addfilterid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=45 ;
Here is the fiddle
Problem is that user can add more than one filter for each adds, that is if the
vehicle has AC,GPS, removable cabin and so on...This data is stored in the adds_filters. So, one add can have many filters.
How the query should look like when user choose that catid is 1, manufacturerid is 1 and then users check filters with ids
67 and 158 for example?
I would prefer view over the query, but i have no idea how can i build such view. Reason from preferring the view is that in such a case, i will be able to use select * instead of complicated queries...
Any help will be deeply appreciated.
With this table structure, you gonna need subqueries for each checked filterid, if you want filterids to be displayed.
Without displaying, you can just use DISTINCT and IN.
Here is the query without displaying filterids
SELECT DISTINCT a.*
FROM adds a
JOIN adds_filters f
ON a.`addid` = f.`addid`
WHERE a.`catid` = 1
AND a.`manufacturerid` = 1
AND f.`filterid` IN (67, 158);
Here is the query, that displays two different filterids:
SELECT t1.*, t2.filterid as filterid2
FROM
(
SELECT DISTINCT a.*,
f.`filterid`
FROM adds a
JOIN adds_filters f
ON a.`addid` = f.`addid`
WHERE a.`catid` = 1
AND a.`manufacturerid` = 1
AND f.`filterid` = 67
) t1
JOIN
(
SELECT DISTINCT a.`addid`,
f.`filterid`
FROM adds a
JOIN adds_filters f
ON a.`addid` = f.`addid`
WHERE a.`catid` = 1
AND a.`manufacturerid` = 1
AND f.`filterid` = 158
) t2
ON t1.addid = t2.addid;