SQL group by merge results - mysql

how to run query select "sub" grouped by "cat" to return something like this:
SQL query:
select sub
from post
where cat = 1
group by id
to return something like:
3,4,9,14,33,22
table "post"
id cat sub
1 1 3,4,9,14
2 2 1,2
3 2 4,5
4 1 33,22
5 3 1,4
thanks,

It is a very bad idea to store lists of things in character strings. For one thing, your ids are integers, but the strings are characters. More importantly, SQL has a great data structure for storing lists -- it is called a table. You should be using a junction table.
But, sometimes you are stuck with the data you have. In that case, you can use group_concat():
select group_concat(sub)
from post
where cat = 1;

Related

Select all rows contains same value in a column

I want to select all package_id that contain product_id 2.
In this case, package_id 1,3,5 has product_id 2
Table: product_package
package_id package_name product_id
---------------------------------------------
1 Gold 1,2,3
2 Platinum 4,5,12
3 Diamond 2,11,5
4 Titanium 3,5
5 Basic 2
I tried:
SELECT
*
FROM
product_package
WHERE product_id IN(2)
It is outputting package_id 3 and 5 only. How do I output this properly?
product_id structure is varchar(256). Should I change the structure or add Foreign keys?
We always recommend not to stored delimited columns see Is storing a delimited list in a database column really that bad?
But you can use FIND_IN_SET but this is always slow
SELECT
*
FROM
product_package
WHERE FIND_IN_SET(2,product_id)
package_id
package_name
product_id
1
Gold
1,2,3
3
Diamond
2,11,5
5
Basic
2
fiddle
First, let me explain what is happening in your query.
You have WHERE product_id IN(2), but product_id is a misnomer and should rather be product_ids, because it is multiple IDs unfortunately stored in a string. IN is made to look up a value in a list. Your list, however, only consists of one element, so you can just as well use the equality operator: WHERE product_id = 2.
What you have is WHERE string = number, so the DBMS has to convert one of the values in order to compare the two. It converts the string to a number (so '2' matches 2 and '002' matches 2, too, as it should). But your strings are not numbers. The DBMS should raise an error on '1,2,3' for instance, because '1,2,3' is not a number. MySQL, however, has a design flaw here and still converts the string, regardless. It just takes as many characters from the left as they still represent a number. '1' does, but then the comma is not considered numerical (yes, MySQL cannot deal with a thousand separator when convertings strings to numbers implicitly). So converting '1,2,3' to a number results in 1. Equally, '2,11,5' results in 2, so rather surprisingly '2,11,5' = 2 in MySQL. This is why you are getting that row.
You ask "Should I change the structure", and the answer to this is yes. So far your table doesn't comply with the first normal form and should thus not exist in a relational database. You'll want two tables instead forming the 1:n relation:
Table: package
package_id
package_name
1
Gold
2
Platinum
3
Diamond
4
Titanium
5
Basic
Table: product_package
package_id
product_id
1
1
1
2
1
3
2
4
2
5
2
12
3
2
3
11
3
5
4
3
4
5
5
2
You ask "or add Foreign keys?", and the answer is and add foreign keys. So with the changed structure you want product_package(product_id) to reference product(product_id) and product_package(package_id) to reference package(package_id).
Disregarding that you should not be storing multiple values in a single field, you can use LIKE operator to achieve what you are looking for. I'm going with assumptions:
all values are delimited with commas
all values are integers
there are no whitespaces (or any other characters besides integers and commas)
select * from product_package
where product_id like '2,%'
or product_id like '%,2,%'
or product_id like '%,2'
or product_id like '2'
Alternatively, you can use REGEXP operator:
select * from product_package
where product_id regexp '^2$|^2,.+|.+,2,.+|.+,2'
References:
MySQL LIKE
MySQL REGEXP

select records in given ids sorting order

i have table lets say - Students,
with 5 records and id(s) are 1 to 5, now i want to select the records - in a way that result should come like given sorting order of id column
id column should be resulted - 5,2,1,3,4
is there any other way to do this - then separate db calls for ids?
single db call ?
I guess if you really want a hard-coded order, you could do something like this:
order by case id
when 5 then 0
when 2 then 1
when 1 then 2
when 3 then 3
when 4 then 4
else 999
end
Or more simply (as #Strawberry points out in the comments):
order BY FIELD(id,4,3,1,2,5) desc

Hive - counting distinct CSVs in one column

One of the hive tables looks something like this:
ID listOfcategories
1 ["a","b","b","a","c","d","d"]
2 ["a","a","a","c","c","c","c","e","e","e"]
3 ["a","b","c"]
The number of comma-separated values is a variable. I want to query the number of distinct categories in each row/ID.
So, my output should look like:
ID numDistCategories
1 4
2 3
3 3
You can use explode to output separate rows for each category and then count distinct to get the result you are looking for.
Something like this.
SELECT
id,
COUNT(DISTINCT(cat)) as numDistCategories
FROM (
SELECT
id,
EXPLODE(listOfcategories) AS cat
FROM myTable) a
GROUP BY id;
Hope that helps.

How to explode in MySQL and use it in the WHERE clause of the query - MySQL

I have a database table as below.
Promotion_Table
id(INT), promotion_name(VARCHAR),......, bungalow_ids(VARCHAR)
We can add a promotion for a bungalow(23). So a row is added with the bungalow id as below.
1, My Promotion, ........, 23
But if I single a promotion is added for a multiple bungalows(23,42) all ids are saved in the bungalow_ids column as below.
2, My Promotion 2, ........, 23 | 42
If a user search for promotion which are for specific bungalow(23) All promotions for the bungalow should be shown in the result.
I have a query as below.
SELECT * FROM Promotion_Table WHERE bungalow_ids = '23'
It only gets 1 rows. But actually 2nd row should be shown too since there is a offer. I can nt use LIKE since it gets wrong records.
Given that I have already referred below links but I have no idea how to use them in the query.
Can you split/explode a field in a MySQL query?
Equivalent of explode() to work with strings in MySQL
How can I fix this? How can I explode the column data and use it in the query ?
Use , to separate the string and try this query
select * from promotion_table where FIND_IN_SET("23",bungalow_ids)
http://sqlfiddle.com/#!2/7bbcb/1
The previous Answer is the right decision but if you insist in your model.
Probably what you want to do is:
SELECT *
FROM Promotion_Table
WHERE bungalow_ids = '23'
OR bungalow_ids LIKE '23,*'
OR bungalow_ids LIKE '*,23'
OR bungalow_ids LIKE '*,23,*'
this assuming the numbers are separated by ",".
But this is the wrong way, make the changes to the DB as stated in the previous answer.
you need to reformat your DB schema.
you need to construct 2 tables one for promotions and one for bangalows.
like below:
promotions: Promotion_id(int), Promotion_desc
bangalows: Bangalow_id(int), Promotion_id(int)
tables example:
promotion :
1 myPromotion
2 secondPromotion
bangalows:
1 1
2 2
3 1
4 1
once you create above two tables, the following query will work and returns 1,3,4:
SELECT Bangalow_id FROM Promotion_Table WHERE bungalow_id = '1'

How to create a mysql join query with hierarchical data

I need to create a join query for hierarchical data across 2 tables. These tables can have unlimited amounts of data and their structures are as follows:
group_id group_name group_order
1 group 1 2
2 group 2 1
field_id field_name parent_group field_order
1 field 1 1 1
2 field 2 2 2
3 field 3 2 1
I am currently able to get the correct format of data using 2 select queries with the second query inside a loop created from the results of the first query on the groups table.
The structure of the data I require from the result is as follows:
-group 2
- field 3
- field 2
- group 1
- field 1
Is it possible to get these results from one mysql query? I have read through the mysql document on hierarchical data by I am confused about how to incorporate the join.
Thanks for looking
You shouldn't need to think about it in terms of hierarchical data, you should just be able to select your fields and join on your group information. Try something like:
SELECT *
FROM Fields AS F
INNER JOIN Groups AS G
ON G.group_id = F.parent_group
ORDER BY group_order, field_order
Then you will get each fields as a row with the applicable group, also in the correct group order. Your loop should be able to handle the display you need.
one method
something that may convince you change your db schema