Trouble writing MySQL query involving ordered data from three tables - mysql

I have a table called tags, like this:
+-------+----------+
| tagID | tagName |
+-------+----------+
| 1 | jewelery |
| 2 | gifts |
| 3 | asdf |
| 4 | fashion |
| 5 | diamonds |
+-------+----------+
Then a table called coupon_tags, like this:
+-------+----------+
| tagID | couponID |
+-------+----------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 2 |
| 5 | 3 |
+-------+----------+
And lastly, a table called coupons, here are the pertinent parts (id is the same as couponID elsewhere):
+----+-----------------+
| id | zone |
+----+-----------------+
| 1 | Los Angeles |
| 2 | Orange County |
| 3 | Los Angeles |
| 5 | Orange County |
| 6 | Orange County |
+----+-----------------+
What I need to write a query for: I want to get tagNames via the first table that correspond to the ordered list of the top 10 most used tagIDs in the second table, but it only looks through couponIDs that match another criteria - that the "zone" be a certain zone. In the end, only the top 10 tagNames from a certain zone will show. I've never done a triple-table query before, any help?
I'm trying to keep this purely SQL, as I had a partially working PHP solution but it was messy and very slow.

SELECT tags.tagName FROM
(SELECT tagID, COUNT(*) FROM
coupon_tags
JOIN coupons ON coupons.couponID = coupon_tags.couponID AND zone = 'Los Angeles'
GROUP BY tagID ORDER BY COUNT(*) DESC LIMIT 10) AS most_used
JOIN tags ON most_used.tagID = tags.tagID

Related

Order by single column using multiple where clauses

This a hard question to know how to ask properly, but here goes...
This is the basic format of my table (the actual table has many rows and multiple lang_ids):
----------------------------------
| id | lang_id | key | text |
----------------------------------
| 1 | 1 | k_foo | foo |
----------------------------------
| 2 | 1 | k_bar | bar |
----------------------------------
| 3 | 2 | k_bar | le bar |
----------------------------------
| 4 | 2 | k_foo | le foo |
----------------------------------
What I want to do is return the rows with WHERE lang_id = 2 but order them by results of WHERE lang_id = 1 like so:
----------------------------------
| id | lang_id | key | text |
----------------------------------
| 4 | 2 | k_foo | le foo |
----------------------------------
| 3 | 2 | k_bar | le bar |
----------------------------------
I am driving myself nuts trying to figure it out. I've searched for hours but keep getting results for ordering by multiple columns instead of multiple results of a single column.
I've tried joining it, unioning it, and subqueries but I either return hundreds of rows, or none!
SELECT
l2.id,
l2.lang_id,
l2.key,
l2.text
FROM
language l1
JOIN
language l2
ON l2.key = l1.key
WHERE
l1.lang_id = 1
AND
l2.lang_id = 2
ORDER BY
l1.id -- Replace with whatever column you actually want to order by.

Query Peformance for Tags

I’m creating a system, backed by a MySQL database, and a question appeared about what would be the best practice.
I have a “group“ entity, which have zero or more "tags".
The tables could be represented by:
Groups
+-------+--------+
| id | name |
+-------+--------+
| 1 | Group1 |
| 2 | Hey Guy|
| 3 | Chacko |
| 4 | Dropo |
+-------+--------+
GroupsTags
+-------+--------+
|idGroup| idTag |
+-------+--------+
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
+-------+--------+
Tags
+-------+--------+
| id | name |
+-------+--------+
| 1 | Health |
| 2 | Happy |
+-------+--------+
The system, during the “group” registration, I want that to autocomplete every key press, showing the most popular tags, similar to StackOverflow. In other words, I have to do a query at database for each letter type, order by popularity.
What solution is the best?
What is the best?
select count(*) as qt,Tags.nome from GroupsTags
inner join Tags
on Tags.id = GroupsTags.idTag
where Tags.name like "phrase%"
group by GroupsTags.idTag
order by qt desc
or, save in the Tags table, the amount of times it was used. Like this
Tags
+-------+--------+--------+
| id | name | qtUsed |
+-------+--------+--------+
| 1 | Health | 2 |
| 2 | Happy | 1 |
+-------+--------+--------+
select * from Tags where name like "phrase%" order by qtUsed desc
I wonder if it is really needed to put the number of times that the tag was used to get a better performance. Would it be a bad practice ?

How to select / join some data from one mySQL innodb table to another with no duplicates and choosing the last inserted row per id

I'm new to mySQL, and I'm trying to be able to either SELECT or CREATE A VIEW with the information I want to retrieve from two tables. SQLfiddle
People Table
| people_id | username | Password | Email |
----------------------------------------------
| 1 | username1 | Password1 | Email1 |
| 2 | username2 | Password2 | Email2 |
| 3 | username3 | Password3 | Email3 |
Profile Table
| people_id | id | age | location | hobbies | about |
----------------------------------------------------------------------------------------------------------------------------
| 1 | 1 | 22 | USA | skiing, snowboarding | I am from the US and I like to snowboard |
| 2 | 2 | 45 | Canada | curling, ice skating, reading | I like to ice skate! |
| 3 | 3 | 38 | USA | tv, movies, you name it | I am from the US and I like to watch the tube |
| 2 | 4 | 45 | Canada | curling, reading | I do not like to ice skate anymore |
| 2 | 5 | 46 | Canada | bowling | Bowling is my new favorite hobby! I just turned 46! |
| 1 | 6 | 22 | Brazil | skiing, snowboarding | I am orginally from the US but I just moved to brazil|
I would like to see/retrieve the data like this :
| people_id | username | age | location | hobbies | about |
------------------------------------------------------------------------------------------------------------------------------------
| 3 | username3 | 38 | USA | tv, movies, you name it | I am from the US and I like to watch the tube |
| 2 | username2 | 46 | Canada | bowling | Bowling is my new favorite hobby! I just turned 46! |
| 1 | username1 | 22 | Brazil | skiing, snowboarding | I am orginally from the US but I just moved to brazil|
So I need to select all the people_id and username from table People and then select the people_id row from Profile where the id is the largest number for each people_id
I've tried
SELECT People.people_id, People.username, Profile.age, Profile.location, Profile.hobbies, Profile.about
FROM People
INNER JOIN Profile
ON People.people_id=Profile.people_id
Which gets me closer to what I want, but I don't want to show duplicate rows, I only want to show the last row inserted into the Profile table for each people_id.
SQLfiddle
The most efficient way to get what you want is to use a not exists condition in the where clause. This definitely takes some getting used to. What the query is going to do is to get the matching row from Profile subject to the condition that no other row has a larger id. This is a round-about way of saying "get the biggest id for each person". But, it happens to produce an efficient query plan (and this is true in most databases, not just MySQL).
SELECT p.people_id, p.username, pr.age, pr.location, pr.hobbies, pr.about
FROM People p INNER JOIN
Profile pr
ON p.people_id = pr.people_id
WHERE NOT EXISTS (SELECT 1
FROM Profile pr2
WHERE pr2.people_id = pr.people_id AND
pr2.id > pr.id
);
SELECT People.people_id, People.username, Profile.age, Profile.location, Profile.hobbies, Profile.about
FROM People
INNER JOIN (SELECT * FROM Profile ORDER BY id DESC) AS Profile
ON People.people_id=Profile.people_id
GROUP BY People.people_id
ORDER BY people_id DESC

mysql select query on two tables

I am trying to get a result from two tables without having a second query nested inside the first query loop.
I have a table products:
product_code_1234 | product_name | otherfields...
And a table categories, where a product can have multiple categories:
category_name_1 | product_code_1234
category_name_2 | product_code_1234
category_name_3 | product_code_1234
Is there a query to get the following result?
product_code_1234 | product_name | ... | category_name_1 | category_name_2 | category_name_3
select * from a,b
will give you all data from table a ,combined with all data from table b.
However if you don't want repetition of data and there isn't any connection between table a and b it can't be done without some union or similar
Assume you have these tables:
+----------------------------+
| PRODUCTS |
+------+-------------+-------+
| code | name | price |
+------+-------------+-------+
| 1 | Bike Helmet | 99.99 |
| 2 | Shirt | 19.99 |
+------+-------------+-------+
+-------------------+
| CATEGORIES |
+------+------------+
| code | category |
+------+------------+
| 1 | Sports |
| 1 | Cycling |
| 1 | Protection |
| 2 | Men |
| 2 | Clothing |
+------+------------+
Here is a query based on another SO answer, that would match your desired result, if my interpretation of it is correct:
SELECT p.code, p.name, p.prize,
(SELECT category FROM categories c WHERE c.code = p.code LIMIT 0, 1) as category1,
(SELECT category FROM categories c WHERE c.code = p.code LIMIT 1, 1) as category2,
(SELECT category FROM categories c WHERE c.code = p.code LIMIT 2, 1) as category3,
FROM products p
This is the result:
+------+-------------+-------+-----------+-----------+------------+
| code | name | price | category1 | category2 | category3 |
+------+-------------+-------+-----------+-----------+------------+
| 1 | Bike Helmet | 99.99 | sports | cycling | protection |
| 2 | Shirt | 19.99 | men | clothing | NULL |
+------+-------------+-------+-----------+-----------+------------+
It is not possible, though, to have a dynamic number of categories in the result. In this case I limited the number to 3, like in your question. There might still be a solution with better performance. Also, this is obviously a nested query and therefore probably not suited for your needs. Still, it's the best I could come up with.
JOIN
There is also the SQL JOIN clause, which might be what you are looking for:
SELECT *
FROM products
NATURAL JOIN categories
You would end up with this result:
+------+-------------+-------+------------+
| code | name | price | category |
+------+-------------+-------+------------+
| 1 | Bike Helmet | 99.99 | sports |
| 1 | Bike Helmet | 99.99 | cycling |
| 1 | Bike Helmet | 99.99 | protection |
| 2 | Shirt | 19.99 | men |
| 2 | Shirt | 19.99 | clothing |
+------+-------------+-------+------------+
I guess that you will have to do two separate queries.
One to retrieve products, one to retrieve the product categories.
Then use any scripting language (like PHP) to achieve what you want with the results (display, export, whatever).

mySQL query; Ignore specific ID values

I need to make a mySQL query and am not sure what the format should be.
Here is the situation, I have a table with the fields - id, name, type
I would use a query similar to the following to get results from the table:
SELECT * FROM table WHERE type='1'
However, I have a list of ID's from another query. These are items that should be excluded from the results.
I'm sure the answer is simple, but I don't know enough about mySQL queries to find the answer.
A simple NOT IN will be what you want :) It lets you send a list of values and makes sure that its not in them :)
SELECT * FROM table WHERE ID NOT IN (1,2,3)
You could also do it with a subquery with something like:
SELECT id FROM table WHERE ID NOT IN (SELECT id FROM table2 WHERE type = 1)
You can use NOT IN query like this:
SELECT * FROM `table` WHERE `type`=1 WHERE `id` NOT IN (SELECT `blocked_ids` FROM `block`);
So, you would be having blocked IDs in the block table! Hope this helps! :)
Consider this table:
+----+-------------+
| id | name |
+----+-------------+
| 1 | America |
| 2 | Europe |
| 3 | India |
| 4 | Japan |
| 5 | Brazil |
| 6 | Switzerland |
| 7 | Syria |
| 8 | Wales |
| 9 | Taiwan |
| 10 | Zaire |
+----+-------------+
And the blocked table:
+-----+
| IDs |
+-----+
| 1 |
| 4 |
| 6 |
| 8 |
| 9 |
+-----+
Now, when I give a query like:
SELECT * FROM `countries` WHERE `id` NOT IN (SELECT * FROM `blocked`);
I get this result:
+----+--------+
| id | name |
+----+--------+
| 2 | Europe |
| 3 | India |
| 5 | Brazil |
| 7 | Syria |
| 10 | Zaire |
+----+--------+
Hope this helps! :)