Query to display latest values based from the latest dates [duplicate] - php

This question already has answers here:
Get the latest date from grouped MySQL data
(7 answers)
Closed 1 year ago.
I'm creating a school project where I need to monitor the member's availability based on their loan transactions.
Now the issue here is when a member already makes tons of transactions, my existing query displays all of the transactions which I only wanted the present status based on their latest date requested of a transaction.
I will provide a screenshot of the issue for more visualization.
This is my query as of now:
$query = $this->db->query("
SELECT * FROM `tbl_members`
LEFT JOIN tbl_loanrequests
on tbl_members.member_id = tbl_loanrequests.member_id
");
And here's the useful information:
CREATE TABLE `tbl_members` (
`member_id` int(11) NOT NULL,
`firstname` varchar(250) NOT NULL,
`lastname` varchar(250) NOT NULL,
`middlename` varchar(250) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `tbl_members` (`member_id`, `firstname`, `lastname`, `middlename`) VALUES
(1, 'Maribeth', 'Cunha', ''),
(2, 'Thelma ', 'Rush  ', ''),
(3, 'Latoria ', 'Shinn', ''),
(4, 'Quinton ', 'Everman', ''),
(5, 'Robert', 'Evermen', '');
CREATE TABLE `tbl_loanrequests` (
`loanreq_id` int(11) NOT NULL,
`member_id` int(11) NOT NULL,
`loanreq_status` varchar(50) NOT NULL,
`date_requested` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `tbl_loanrequests` (`loanreq_id`, `member_id`, `loanreq_status`, `date_requested`) VALUES
(2, 1, 'Paid', '2021-05-06'),
(3, 2, 'For Release', '2021-05-06'),
(4, 3, 'Pending', '2021-05-06'),
(5, 5, 'Ongoing', '2021-05-06'),
(6, 1, 'Cancelled', '2021-05-07');
http://sqlfiddle.com/#!9/7647a4/1
This is the preview where member_id #1 supposed to be displaying only one status which is the Cancelled since it got the latest date_requested. On the left side, it displays Clear though but that's a way for me to monitor if a member is able to file a loan.

I considered that your loanreq_id is incremented and thus that the highest for each member always contain the highest loanreq date for that member. If not I can adapt
The trick is to determine the highest loanreq_id for each member using a MAX...GROUP BY:
SELECT member_id, MAX(loanreq_id) AS last_loanreq_id
FROM tbl_loanrequests
GROUP BY member_id
You should then join the result of this query to only keep the latest loanreq of each member. Your query becomes :
SELECT m.*, l.*
FROM `tbl_members` m
LEFT JOIN
(
SELECT member_id, MAX(loanreq_id) AS last_loanreq_id
FROM tbl_loanrequests
GROUP BY member_id
) lm ON lm.member_id = m.member_id
LEFT JOIN tbl_loanrequests l on l.loanreq_id = lm.last_loanreq_id

Related

LEFT JOIN with condition is not returning data desired

I would like to do a left join using MYSQL. Currently I have a table something like this:
CREATE TABLE `books` (
`bookId` int(11) NOT NULL,
`bookTitle` varchar(100) NOT NULL,
`bookAuthor` varchar(100) NOT NULL,
`bookStatus` tinyint(1) NOT NULL,
`bookDeleteFlag` tinyint(1) NOT NULL
);
CREATE TABLE `lends` (
`lendId` int(11) NOT NULL,Primary
`lendBookId` int(11) NOT NULL,
`lendBorrowerName` Varchar(100) NOT NULL,
`lendBorrowStatus` int(11) NOT NULL,
`lendReturnStatus` int(11) NOT NULL,
);
insert into books values (1, 'The Da Vinci Code', 'Dan Brown', 1,0)
insert into books values (2, 'Theory of Relativity', 'Albert Einstein', 1,0)
insert into books values (3, 'Harry Potter', 'J K Rowling', 1,0)
insert into books values (1, '1', 'Chris', 1,1)
insert into books values (2, '1', 'Lilly', 1,0)
insert into books values (3, '2', 'Chris', 1,0)
insert into books values (3, '3', 'Chris', 1,1)
The desired output like this
bookId bookTitle availability
-----------------------------------------------
1 The Da Vinci Code 0
2 Theory of Relativity 0
3 Harry Potter 1
I am basically developing a Library management module. I want the availability of that book to be listed on book search page.
The current code that i have is:
SELECT B.bookTitle,
L.lendBorrowerName AS takenName,
count(L.lendStatus) AS taken
FROM books as B
LEFT JOIN lends AS L ON B.bookId = L.lendBookID
WHERE L.lendReturnStatus = 0 // if i remove this code, all rows in books table is listed. However i loose the ability to check the availability of that book
GROUP BY B.bookTitle
What is the typical solution for this problem?
Thanks in advance.
You need to move the condition in the where clause to the on clause. When no rows match, then the column has a value of NULL and the WHERE condition fails:
SELECT B.bookTitle,
L.lendBorrowerName AS takenName,
count(L.lendStatus) AS taken
FROM books as B LEFT JOIN
lends AS L
ON B.bookId = L.lendBookID AND
L.lendReturnStatus = 0
GROUP BY B.bookTitle;
SELECT B.bookTitle,
sum(L.lendReturnStatus = 0) = 0 AS availibility
FROM books as B
LEFT JOIN lends AS L ON B.bookId = L.lendBookID
GROUP BY B.bookTitle

MySQL Query to retrieve results based on multiple Tags

If have to deal with an existing database structure and try to find an efficient way to select files based on their Tags.
One table has the "Files", one has the "Tag Description" and the third one holds all "Tags" related to a file.
How can I select all files with:
Language = 'ENG' and Measure = 'METRIC' and Category = 'Type1'? (So result should be one File: ID 100).
This is a simplified version of the 3 tables concerned:
CREATE TABLE IF NOT EXISTS `files` (
`file_id` int(11) NOT NULL DEFAULT '0',
`file_name` varchar(64) DEFAULT NULL,
PRIMARY KEY (`file_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `files` (`file_id`, `file_name`) VALUES
(100, 'testfile_1'),
(200, 'testfile_2'),
(300, 'testfile_3'),
(400, 'testfile_4');
CREATE TABLE IF NOT EXISTS `tag_parents` (
`parent_id` int(11) NOT NULL DEFAULT '0',
`parent_name` varchar(64) DEFAULT NULL,
PRIMARY KEY (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `tag_parents` (`parent_id`, `parent_name`) VALUES
(1, 'Language'),
(2, 'Measure'),
(3, 'Category');
CREATE TABLE IF NOT EXISTS `tags` (
`tag_id` int(11) NOT NULL DEFAULT '0',
`file_id` int(11) DEFAULT NULL,
`tag_parent_id` int(11) DEFAULT NULL,
`tag_value` varchar(64) DEFAULT NULL,
PRIMARY KEY (`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `tags` (`tag_id`, `file_id`, `tag_parent_id`, `tag_value`) VALUES
(1, 100, 1, 'ENG'),
(2, 200, 1, 'ENG'),
(3, 300, 1, 'FRA'),
(4, 400, 1, 'DEU'),
(5, 100, 2, 'METRIC'),
(6, 200, 2, 'IMPERIAL'),
(7, 300, 2, 'METRIC'),
(8, 400, 2, 'IMPERIAL'),
(9, 100, 3, 'Type1'),
(10, 200, 3, 'Type3'),
(11, 300, 3, 'Type1'),
(12, 400, 3, 'Type1');
Any help is appreciated. Thank you! ( I have failed with all my trials so far or they have been far to slow (with subselects)).
It makes me think of meta-models where the properties of an object (file in this case) are not columns but values to be looked up in the tags. It will always be slower than having the columns directly in the table, but you should be able to get it to work reasonably. I see tag_parents as tag_type. The following (fiddle here) should work:
select f.*
from files f
where exists ( -- it should have the "Category"."Type1"
select parent_id
from tag_parents categoryT, tags category
where categoryT.parent_name="Category"
and category.tag_parent_id=categoryT.parent_id
and category.tag_value="Type1"
and category.file_id=f.file_id
)
and exists ( -- as well as "Language"."ENG"
select parent_id
from tag_parents languageT, tags language
where languageT.parent_name="Language"
and language.tag_parent_id=languageT.parent_id
and language.tag_value="ENG"
and language.file_id=f.file_id
)
and exists ( -- as well as "Measure"."METRIC"
select parent_id
from tag_parents measureT, tags measure
where measureT.parent_name="Measure"
and measure.tag_parent_id=measureT.parent_id
and measure.tag_value="METRIC"
and measure.file_id=f.file_id
)
You could simplify your life by defining some views such as Category, Language and Measure (and whatever other tag_parents you'll have). This will make queries more readable. With three views category, measure and language you could be write:
select * from files f, category c, measure m, `language` l
where f.file_id=c.file_id and c.value="Type1"
and f.file_id=l.file_id and l.value="ENG"
and m.file_id=l.file_id and m.value="METRIC";
Or even better, if you have a fixed number of these properties, you could define a view similar to the query at the top, but using outer joins rather than exists, with nullable columns category, measure and language:
create view filesView (file_id, category, measure, `language`) as
select f.file_id, c.tag_value, m.tag_value, l.tag_value
from files f
left outer join (tags c, tag_parents ct) on c.file_id=f.file_id
and c.tag_parent_id=ct.parent_id
and ct.parent_name="Category"
left outer join (tags l, tag_parents lt) on l.file_id=f.file_id
and l.tag_parent_id=lt.parent_id
and lt.parent_name="Language"
left outer join (tags m, tag_parents mt) on m.file_id=f.file_id
and m.tag_parent_id=mt.parent_id
and mt.parent_name="Measure";
And then you can write:
select file_id, category, measure, `language`
from filesView
where category="Type1"
and `language`="ENG"
and measure="METRIC";
(Sorry got carried away a bit.)

Need MySQL optimization for complex search on EAV structured data

I have a large database with EAV structured data that has to be searchable and pageable. I tried every trick in my book to get it fast enough, but under certain circumstances, it still fails to complete in a reasonable time.
This is my table structure (relevant parts only, ask away if you need more):
CREATE TABLE IF NOT EXISTS `object` (
`object_id` bigint(20) NOT NULL AUTO_INCREMENT,
`oid` varchar(32) CHARACTER SET utf8 NOT NULL,
`status` varchar(100) CHARACTER SET utf8 DEFAULT NULL,
`created` datetime NOT NULL,
`updated` datetime NOT NULL,
PRIMARY KEY (`object_id`),
UNIQUE KEY `oid` (`oid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `version` (
`version_id` bigint(20) NOT NULL AUTO_INCREMENT,
`type_id` bigint(20) NOT NULL,
`object_id` bigint(20) NOT NULL,
`created` datetime NOT NULL,
`status` varchar(100) CHARACTER SET utf8 DEFAULT NULL,
PRIMARY KEY (`version_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `value` (
`value_id` bigint(20) NOT NULL AUTO_INCREMENT,
`object_id` int(11) NOT NULL,
`attribute_id` int(11) NOT NULL,
`version_id` bigint(20) NOT NULL,
`type_id` bigint(20) NOT NULL,
`value` text NOT NULL,
PRIMARY KEY (`value_id`),
KEY `field_id` (`attribute_id`),
KEY `action_id` (`version_id`),
KEY `form_id` (`type_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This is a sample object. I have around 1 million of those in my database. each object may have different number of attributes with different attribute_id
INSERT INTO `owner` (`owner_id`, `uid`, `status`, `created`, `updated`) VALUES (1, 'cwnzrdxs4dzxns47xs4tx', 'Green', NOW(), NOW());
INSERT INTO `object` (`object_id`, `type_id`, `owner_id`, `created`, `status`) VALUES (1, 1, 1, NOW(), NOW());
INSERT INTO `value` (`value_id`, `owner_id`, `attribute_id`, `object_id`, `type_id`, `value`) VALUES (1, 1, 1, 1, 1, 'Munich');
INSERT INTO `value` (`value_id`, `owner_id`, `attribute_id`, `object_id`, `type_id`, `value`) VALUES (2, 1, 2, 1, 1, 'Germany');
INSERT INTO `value` (`value_id`, `owner_id`, `attribute_id`, `object_id`, `type_id`, `value`) VALUES (3, 1, 3, 1, 1, '123');
INSERT INTO `value` (`value_id`, `owner_id`, `attribute_id`, `object_id`, `type_id`, `value`) VALUES (4, 1, 4, 1, 1, '2012-01-13');
INSERT INTO `value` (`value_id`, `owner_id`, `attribute_id`, `object_id`, `type_id`, `value`) VALUES (5, 1, 5, 1, 1, 'A cake!');
Now on to my current mechanism. My first try was the typical approach to Mysql. Do one huge SQL with loads of joins on anything I require. Complete desaster! Took way to long to load and even crashed the PHP and MySQL servers due to exhausted RAM.
So I split my queries up into several steps:
1 Determine all needed attribute_ids.
I can look them up in another table that references the type_id of an object. The result is a list of attribute_ids. (this table is not very relevant to the performance, so it's not included in my sample.)
:type_id contains all type_ids from any objects I want to include in my search. I already got this information in my application. So this is inexpensive.
SELECT * FROM attribute WHERE form_id IN (:type_id)
Result is an array of type_id integers.
2 Search for matching objects
A big SQL query is compiled that adds one INNER JOIN for each and every condition I want. This sounds horrible, but in the end, it was the fastest method :(
A typical generated query might look like this. The LIMIT sadly is necessary or I will potentially get so many IDs that the resulting array makes PHP explode or break the IN statement in the next Query:
SELECT DISTINCT `version`.object_id FROM `version`
INNER JOIN `version` AS condition1
ON `version`.version_id = condition1.version_id
AND condition1.created = '2012-03-04' -- Filter by version date
INNER JOIN `value` AS condition2
ON `version`.version_id = condition2.version_id
AND condition2.type_id IN (:type_id) -- try to limit joins to object types we need
AND condition2.attribute_id = :field_id2 -- searching for a value in a specific attribute
AND condition2.value = 'Munich' -- searching for the value 'Munich'
INNER JOIN `value` AS condition3
ON `version`.version_id = condition3.version_id
AND condition3.type_id IN (:type_id) -- try to limit joins to object types we need
AND condition3.attribute_id = :field_id3 -- searching for a value in a specific attribute
AND condition3.value = 'Green' -- searching for the value 'Green'
WHERE `version`.type_id IN (:type_id) ORDER BY `version`.version_id DESC LIMIT 10000
The result will contain all object_ids from any object I might need. I am selecting object_ids and not version_ids as I need to have all versions of matching objects, regardless of which version matched.
3 Sort and page results
Next I will create a query that sorts the objects by a certain attribute and then pages the resulting array.
SELECT DISTINCT object_id
FROM value
WHERE object_id IN (:foundObjects)
AND attribute_id = :attribute_id_to_sort
AND value > ''
ORDER BY value ASC LIMIT :limit OFFSET :offset
The result is a sorted and paged list of object ids from former search
4 Get our complete objects, versions and attributes
In the last step, I will select all values for any objects and versions the former queries found.
SELECT `value`.*, `object`.*, `version`.*, `type`.*
`object`.status AS `object.status`,
`object`.flag AS `object.flag`,
`version`.created AS `version.created`,
`version`.status AS `version.status`,
FROM version
INNER JOIN `type` ON `version`.form_id = `type`.type_id
INNER JOIN `object` ON `version`.object_id = `object`.object_id
LEFT JOIN value ON `version`.version_id = `value`.version_id
WHERE version.object_id IN (:sortedObjectIds) AND `version.type_id IN (:typeIds)
ORDER BY version.created DESC
The result will then be compiled via PHP into nice object->version->value array structures.
Now the question:
Can this whole mess be accelerated in any way?
Can I somehow remove the LIMIT 10000 restriction from my search query?
If all else fails, maybe switch database technology? See my other question: Database optimized for searching in large number of objects with different attributes
Real Life samples
Table sizes: object - 193801 rows, version - 193841 rows, value - 1053928 rows
SELECT * FROM attribute WHERE attribute_id IN (30)
SELECT DISTINCT `version`.object_id
FROM version
INNER JOIN value AS condition_d4e328e33813
ON version.version_id = condition_d4e328e33813.version_id
AND condition_d4e328e33813.type_id IN (30)
AND condition_d4e328e33813.attribute_id IN (377)
AND condition_d4e328e33813.value LIKE '%e%'
INNER JOIN value AS condition_2c870b0a429f
ON version.version_id = condition_2c870b0a429f.version_id
AND condition_2c870b0a429f.type_id IN (30)
AND condition_2c870b0a429f.attribute_id IN (376)
AND condition_2c870b0a429f.value LIKE '%s%'
WHERE version.type_id IN (30)
ORDER BY version.version_id DESC LIMIT 10000 -- limit to 10000 or it breaks!
Explain:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE condition_2c870b0a429f ref field_id,action_id,form_id field_id 4 const 178639 Using where; Using temporary; Using filesort
1 SIMPLE action eq_ref PRIMARY PRIMARY 8 condition_2c870b0a429f.action_id 1 Using where
1 SIMPLE condition_d4e328e33813 ref field_id,action_id,form_id action_id 8 action.action_id 11 Using where; Distinct
objects search completed (Peak RAM: 5.91MB, Time: 4.64s)
SELECT DISTINCT object_id
FROM version
WHERE object_id IN (193793,193789, ... ,135326,135324) -- 10000 ids in here!
ORDER BY created ASC
LIMIT 50 OFFSET 0
objects sort completed (Peak RAM: 6.68MB, Time: 0.352s)
SELECT `value`.*, object.*, version.*, type.*,
object.status AS `object.status`,
object.flag AS `object.flag`,
version.created AS `version.created`,
version.status AS `version.status`,
version.flag AS `version.flag`
FROM version
INNER JOIN type ON version.type_id = type.type_id
INNER JOIN object ON version.object_id = object.object_id
LEFT JOIN value ON version.version_id = `value`.version_id
WHERE version.object_id IN (135324,135326,...,135658,135661) AND version.type_id IN (30)
ORDER BY quality DESC, version.created DESC
objects load query completed (Peak RAM: 6.68MB, Time: 0.083s)
objects compilation into arrays completed (Peak RAM: 6.68MB, Time: 0.007s)
Just try to add an EXPLAIN before your search query :
EXPLAIN SELECT DISTINCT `version`.object_id FROM `version`, etc ...
then check the results in the "Extra" column, it will give you some clues to speedup your query, like adding INDEX on the right fields.
Also some times you can removeINNER JOIN, get more results in your Mysql response and filter the big array by processing with PHP loops.
I would start by trying to have covering indexes (ie: all columns to match the criteria you are querying on and even pulling out as result). This way the engine does not have to go back to the raw page data.
Since you need the "object_id" from version, and using the "version_id" as join basis to the other tables. Your version table also has a WHERE clause on the TYPE_ID, so I would have an index on
version table -- (object_id, version_id, type_id)
For your "value" table, match there too for criteria
value table -- ( version_id, type_id, attribute_id, value, created )

MySQL - Conversation History overview - Selecting multiple latest items from table

I have the joy of recreating the phone, by building a customized messaging system in PHP that uses an API to send and receive messages.
I'm trying to emulate the functionality found in Facebook messaging on their desktop site.
[Col 1] [Col 2]
A list of the Conversation View.
latest messages
received in order
of Newest to oldest
I am having issues with the Query for the first column.
I currently have a table in MySQL with the following structure:
CREATE TABLE IF NOT EXISTS `History` (
`ID` int(10) NOT NULL AUTO_INCREMENT COMMENT 'MessageID',
`Sender` varchar(10) NOT NULL,
`Recipient` varchar(10) NOT NULL,
`ExtReference` int(20) DEFAULT NULL,
`Date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`Status` varchar(100) NOT NULL,
`userid` int(3) NOT NULL,
`Message` longtext NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=609 ;
With a sample Date set like:
INSERT INTO `History` (`ID`, `Sender`, `Recipient`, `ExtReference`, `Date`, `Status`, `userid`, `Message`) VALUES
(1, '0412345678', '0468888888', 33845909, '2013-03-17 04:17:34', '1', 11, 'Just testing....'),
(2, '0412345678', '0400222333', 33845910, '2013-03-17 04:17:35', '1', 11, 'Amazing'),
(3, '0412345678', '0411111111', 33847419, '2013-03-17 04:46:04', '1', 8, 'Nothing here to see'),
(4, '0412345678', '0400222333', 33850155, '2013-03-17 06:31:57', '1', 12, 'Hello there Mr IT Guru :-)'),
(5, '0400222333', '0412345678', 33850179, '2013-03-17 06:33:21', '1', 12, '[Write message here]'),
(6, '0412345678', '0411111111', 33955423, '2013-03-23 01:26:22', '1', 8, 'Hello Charles'),
(7, '0412345678', '0411111111', 33959071, '2013-03-23 03:08:26', '1', 13, 'Sample Message'),
(8, '0400222333', '0412345678', 33964111, '2013-03-23 05:27:51', '1', 13, 'How do I use this system?'),
(9, '0400222333', '0412345678', 34107503, '2013-03-30 03:13:38', '1', 12, 'Is this thing on?'),
(10, '0412345678', '0401411210', 34230869, '2013-03-05 00:18:09', '1', 16, 'Hello')
(In this example my number is: 0412345678).
SQL Fiddle here: http://sqlfiddle.com/#!2/29197/1/0
I have worked out how to get a list of all the unique numbers used across both the Sender and Recipient columns:
SELECT DISTINCT `Sender` AS phoneID FROM `History`
UNION
SELECT DISTINCT `Recipient` AS phoneID FROM `History`
But I can't work how to attach the latest Date and message to this data.
If I focus on either just messages sent to me or sent by me I can get somewhere with these two:
SELECT `ID`, `Sender`, `Recipient`, MAX(`Date`), `Message` FROM History
GROUP BY Sender
ORDER BY `History`.`Date` DESC
or
SELECT `ID`, `Sender`, `Recipient`, MAX(`Date`), `Message`, `Status` FROM History
GROUP BY Recipient
ORDER BY `History`.`Date` DESC
Any thoughts?
I can recreate the History table layout if needed.
I'll also need to try and join the phone number with a persons name in a Contacts table later on down the track.
Thanks
Charlie
Possibly not the best way but you could combine the two queries you have. Something like:
SELECT `ID`, `Sender`, `Recipient`,`Date`,`Message`,`Status` FROM
(
SELECT `ID`, `Sender`, `Recipient`, `Date`, `Message`,`Status` FROM History
WHERE Sender = "0412345678"
GROUP BY Sender
UNION
SELECT `ID`, `Sender`, `Recipient`, MAX(`Date`), `Message`, `Status` FROM History
WHERE Recipient = "0412345678"
GROUP BY Recipient
) res
GROUP BY res.ID
ORDER BY res.Date DESC
Note that this is for a specific number. You could remove the WHERE clauses if this wasn't needed.

MySQL query - how to get a count of number of related tags

I am struggling figuring out a good way to query my required data. I am using mySQL and php. Currently, I am making multiple queries and using a bunch of for each loops, however, I still can't get my necessary output.
This might be tough question, so I appreciate anyone who puts in some effort to figure it out!
My current tables are as follows:
topics_keywords (t_k_id, topic_id, keyword_id)
keywords (keyword_id, keyword)
topics (topic_id, subject, etc)
table topics_keyword is going to have multiple keywords associated with the same topic_id.
table keywords will only have define a single keyword for each keyword_id.
If someone queries for a specific keyword(i.e. sports), I would like to return a list of all associated keywords that relate to the topic_id.
In the below SQL, you'll see that topic 3 is associated with keyword_id's 3(sports) and 4(baseball). However, note that it is also associated with keyword_id 2(hello).
I simply need a count of how many times 'sports' is associated with baseball. I say simply, but i can't figure out an easy way to do it.
The final output, based on the data below, would need to look something like this:
search term: 'baseball'
final output:
count | keyword
----------------
sports | 2
hello | 1
Heres some mySQL to help go through the data:
CREATE TABLE IF NOT EXISTS `keywords` (
`keyword_id` int(11) NOT NULL AUTO_INCREMENT,
`keyword` varchar(64) NOT NULL,
PRIMARY KEY (`keyword_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;
--
-- Dumping data for table `keywords`
--
INSERT INTO `keywords` (`keyword_id`, `keyword`) VALUES
(1, 'thebump'),
(2, 'hello'),
(3, 'baseball'),
(4, 'sports'),
(5, 'manga'),
(6, 'naruto'),
(7, 'one piece');
-- --------------------------------------------------------
--
-- Table structure for table `topics_keywords`
--
CREATE TABLE IF NOT EXISTS `topics_keywords` (
`t_k_id` int(11) NOT NULL AUTO_INCREMENT,
`topics_id` int(11) NOT NULL,
`keyword_id` int(11) NOT NULL,
PRIMARY KEY (`t_k_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
--
-- Dumping data for table `topics_keywords`
--
INSERT INTO `topics_keywords` (`t_k_id`, `topics_id`, `keyword_id`) VALUES
(1, 1, 1),
(2, 2, 2),
(3, 3, 3),
(4, 3, 4),
(5, 4, 3),
(6, 5, 3),
(7, 5, 4),
(8, 6, 3),
(9, 6, 4),
(10, 3, 2);
Thanks very much!
Try this:
SELECT keyword,
Count(*)
FROM topics_keywords
INNER JOIN keywords
ON topics_keywords.keyword_id = keywords.keyword_id
INNER JOIN (SELECT k1.keyword_id AS keyword_id,
topics_keywords.topics_id
FROM keywords k1
INNER JOIN topics_keywords
ON topics_keywords.keyword_id = k1.keyword_id
WHERE keyword = 'baseball') AS temp
ON temp.keyword_id != keywords.keyword_id
AND temp.topics_id = topics_keywords.topics_id
GROUP BY keyword
SQLFiddle DEMO
EDIT: You can try this also:
SELECT keywords.keyword,
Count(*)
FROM topics_keywords
INNER JOIN keywords
ON topics_keywords.keyword_id = keywords.keyword_id
INNER JOIN keywords k1
ON k1.keyword_id != keywords.keyword_id
INNER JOIN topics_keywords t1
ON t1.keyword_id = k1.keyword_id
AND t1.topics_id = topics_keywords.topics_id
WHERE k1.keyword = 'baseball'
GROUP BY keyword
SQLFiddle DEMO
I personally feel that first one should be faster, but if you can benchmark it post the results that would be good.

Categories