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).
Related
These are my tables:
language language_person person
+----+----------+ +----+-----------+-----------+ +----+-----------------+
| id | name | | id | languageId| personId | | id | name |
+----+----------+ +----+-----------+-----------+ +----+-----------------+
| 1 | english | | 1 | 1 | 1 | | 1 | luca |
+----+----------+ +----+-----------+-----------+ +----+-----------------+
| 2 | german | | 2 | 2 | 1 | | 2 | sara |
+----+----------+ +----+-----------+-----------+ +----+-----------------+
| 3 | italian | | 3 | 3 | 1 | | 3 | michael |
+----+----------+ +----+-----------+-----------+ +----+-----------------+
| 4 | 3 | 2 |
+----+-----------+-----------+
| 5 | 2 | 3 |
+----+-----------+-----------+
Currently I'm loading with JPA a person and a list of the languages spoken by this person.
Every person talks at least one language. Now I would like to implement a query, to get all the person that talks exactly and only the same languages. In case of 'Luca', I search someone that talks english AND german AND italian. When searching with a query like WHERE languageId IN (1, 2, 3) I obviously get all person back that talk at least one of the languages. Also when searching for someone like 'sara', I search for someone talking ONLY italian, no other language.
It's completely out of my understanding, so any help is higly appreciated.
I think the simplest way is to use aggregation and window functions:
select id, name
from (select p.id, p.name,
group_concat(lp.languageid order by lp.languageid) as languageids,
max(case when p.name = 'Luca' then group_concat(lp.languageid order by lp.languageid) end) over () as luca_languageids
from language_person lp join
person p
on lp.personid = p.id
group by p.id, p.name
) p
where languageids = luca_languageids;
I have two tables users and services and i am try to write a single query that will create a new column skills. The values in the column skills will be the service_title which maps to the service_id stored in user_skills.
Below are the examples of a the tables used:
Table users:
+---------+---------------+----------------+----------------+
| id | user_fname | user_lname | user_skills |
+---------+---------------+----------------+----------------+
| 1 | kiran | bhattarai | 1,2 |
| 2 | sujan | bhattarai | 2,4 |
| 3 | manorath | dad | 1,2,3,4 |
| 4 | bhagawoti | mom | 2,3 |
+---------+---------------+----------------+----------------+
Table services:
+-----------------+------------------+
| service_id | service_title |
+-----------------+------------------+
| 1 | cook |
| 2 | clean |
| 3 | grocessery |
| 4 | teach |
+-----------------+------------------+
Currently i am using this query:
SELECT users.user_fname,
users.user_lname,
(SELECT GROUP_CONCAT(service_title)
FROM `services`
WHERE `service_id` IN (1,2,3,4)) as skills
FROM users
WHERE
id =3;
Result of the above query:
+---------------+----------------+----------------------------------------+
| user_fname | user_lname | skills |
+---------------+----------------+----------------------------------------+
| manorath | dad | cook,clean,grocessery,teach |
+---------------+----------------+----------------------------------------+
Instead of using the IN (1,2,3,4) I tried IN (users.user_skills) because the values in user_skills changes all the time and the result was:
+---------------+----------------+----------------------------------------+
| user_fname | user_lname | skills |
+---------------+----------------+----------------------------------------+
| manorath | dad | cook |
+---------------+----------------+----------------------------------------+
Every time a new service is added i have to add that service_id in the IN (1,2,3,4,new service id) of my query which is not a proper solution. I have already tried using php and another query to do solve this, the disadvantage of doing that is it is slowing down the process. How should i solve this problem in a single query.
You can use FIND_IN_SET() to JOIN the two tables.
SELECT
u.user_fname,
u.user_lname,
GROUP_CONCAT(s.service_title) as skills
FROM users u
LEFT JOIN services s
ON FIND_IN_SET(s.service_id, u.user_skills)
WHERE u.id = 3
Note that a JOIN with a FIND_IN_SET() condition cannot utilize any index. And that can lead to poor performance.
In general it's a bad idea to store relations in a separated string column. See Is storing a delimited list in a database column really that bad?.
You should normalize your design and create a separate table for your many-to-many relation. The table would look like
Table users_services:
+---------+------------+
| user_id | service_id |
+---------+------------+
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
| 2 | 4 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
| 3 | 4 |
| 4 | 2 |
| 4 | 3 |
+---------+------------+
And the query would be
SELECT
u.user_fname,
u.user_lname,
GROUP_CONCAT(s.service_title) as skills
FROM users u
LEFT JOIN users_services us ON us.user_id = u.id
LEFT JOIN services s ON s.service_id = us.service_id
WHERE u.id = 3
I have a table of PRODUCTS
+------------+---------------+---------------+
| ProductCod | unitPrice | name |
+------------+---------------+---------------+
| 1 | 30 | some |
| 2 | 20 | poor |
| 3 | 10 | example |
+------------+---------------+---------------+
Another of SALES (which I believe it's not needed) and some other to register a n..m relationship
+------------+----------+------------+
| quantity | sellCode | productCod |
+------------+----------+------------+
| 3 | 1 | 1 |
| 5 | 1 | 2 |
| 4 | 2 | 2 |
| 4 | 2 | 3 |
| 4 | 2 | 3 |
+------------+----------+------------+
How can I select a list of products and how many were sold at all registers?
I would like something like:
+---------+------+
| name | sold |
+---------+------+
| some | 3 |
| poor | 9 |
| example | 8 |
+---------+------+
Using a INNER JOIN is more exact here.
Query
SELECT
products.name
, SUM(sales.quantity) AS sold
FROM
products
INNER JOIN
sales
USING(productCod)
GROUP BY
products.name
ORDER BY
products.ProductCod ASC
Or
SELECT
products.name
, SUM(sales.quantity) AS sold
FROM
products
INNER JOIN
sales
ON
products.productCod = sales.productCod
GROUP BY
products.name
ORDER BY
products.ProductCod ASC
Results
| name | sold |
|---------|------|
| some | 3 |
| poor | 9 |
| example | 8 |
see demo http://sqlfiddle.com/#!9/10cd3e/5
select p.Name, sum(s.Quantity) as sold
from Products p
left join Sales s on p.ProductCod = s.ProductCod
group by p.ProductCod, p.Name;
What we are doing is first to join two tables using productCod common field. We are using LEFT join, because there might be products that are not sold at all yet. Then we sum the quantities grouping by productCod (and Name. We had to include it in the list because it is not an aggregation expression - and there is a single Name per productCod). This works right, because there is a 1 to many relation between products and sales. If there were a many to many relation then the result would be wrong.
EDIT: Check this SQLFiddle sample for a good formatting.
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 ?
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