comma separated field to compare in mysql - mysql

I searched so much to find an answer but i can't.Here is my question
I have a table named main_table like this:
╔════╦════════════════╦
║ id ║ seat_id ║
╠════╬════════════════╬
║ 1 ║ 274115, ║
║ 2 ║ 274116,274117,║
║ 3 ║ 274113,274114, ║
╚════╩════════════════╩
These seat_id's are primary key of another table named sub_table
╔═════════╦════════════════╦
║ seat_id ║ seat ║
╠═════════╬════════════════╬
║ 274115 ║ 186 ║
║ 274116 ║ 187 ║
║ 274117 ║ 188 ║
║ 274118 ║ 159 ║
╚═════════╩════════════════╩
I want all the seat related to main_table's seat_id
╔════════════╗
║ seat ║
╠════════════╣
║ 186 ║
║ 187 ║
║ 188 ║
╚════════════╝
What i have tried so far is with sub query
select seat from sub_table where seat_id in(select seat_id from main_table)
That's not helping me

You can use FIND_IN_SET:
SELECT seat
FROM sub_table AS t1
WHERE EXISTS (SELECT 1
FROM main_table AS t2
WHERE FIND_IN_SET(t1.seat_id, t2.seat_id) <> 0)
However, I would suggest normalizing table main_table, as it is always a bad idea to store comma separated values in a single field like you do.
Demo here

First of all u didnt normalize your table so u cant use joins
and query u used "select seat_id from main_table" --> is not an array .
Try to pass array
select seat from sub_table where seat_id in($array)

Related

MySQL - Merge rows in table based on multiple criteria

I'd like to merge rows based on multiple criteria, essentially removing duplicates where I get to define what "duplicate" means. Here is an example table:
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 1 ║ John ║ 11 ║ 5 ║
║ 2 ║ John ║ 11 ║ 5 ║
║ 3 ║ John ║ 11 ║ 6 ║
║ 4 ║ Sam ║ 14 ║ 7 ║
║ 5 ║ Sam ║ 14 ║ 7 ║
╚═════╩═══════╩═════╩═══════╝
In my example, let's say I want to merge on name and age but ignore grade. The result should be:
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 1 ║ John ║ 11 ║ 5 ║
║ 3 ║ John ║ 11 ║ 6 ║
║ 4 ║ Sam ║ 14 ║ 7 ║
╚═════╩═══════╩═════╩═══════╝
I don't particularly care if the id column is updated to be incremental, but I suppose that would be nice.
Can I do this in MySQL?
My suggestion, based on my above comment.
SELECT distinct name, age, grade
into tempTable
from theTable
This will ignore the IDs and give you only a distinct dump, and into a new table.
Then you can either drop the old and, and rename the new one. Or truncate the old one, and dump this back in.
You could just delete the duplicates in place like this:
delete test
from test
inner join (
select name, age, grade, min(id) as minid, count(*)
from test
group by name, age, grade
having count(*) > 1
) main on test.id = main.minid;
Example: http://sqlfiddle.com/#!9/f1a38/1

Groupwise-max on count() with nested subqueries

My head is turning to mush when trying to get this nesting around my head.
So basically I got 2 tables:
Brokers, which is my "user" table:
╔══════════╦════════════╦
║ ID ║ EMAIL ║
╠══════════╬════════════╬
║ 1 ║ 1#email.co ║
║ 2 ║ 2#email.co ║
║ 3 ║ 3#email.co ║
╚══════════╩════════════╝
Houses, which is houses that the users have added. Currently user and house is connected by the email column (I know, makes more sense to do with a ID):
╔══════════╦════════════╦════════════╦
║ ID ║ TYPE ║ EMAIL ║
╠══════════╬════════════╬════════════╬
║ 1 ║ 1 ║ 1#email.co ║
║ 2 ║ 3 ║ 1#email.co ║
║ 3 ║ 2 ║ 1#email.co ║
║ 4 ║ 3 ║ 1#email.co ║
║ 5 ║ 3 ║ 1#email.co ║
║ 6 ║ 2 ║ 1#email.co ║
║ 7 ║ 3 ║ 1#email.co ║
║ 8 ║ 1 ║ 2#email.co ║
║ 9 ║ 1 ║ 2#email.co ║
║ 10 ║ 2 ║ 2#email.co ║
║ 11 ║ 2 ║ 2#email.co ║
║ 12 ║ 3 ║ 2#email.co ║
║ 13 ║ 3 ║ 3#email.co ║
║ 14 ║ 2 ║ 3#email.co ║
║ 15 ║ 3 ║ 3#email.co ║
║ 16 ║ 1 ║ 3#email.co ║
║ 17 ║ 3 ║ 3#email.co ║
║ 18 ║ 2 ║ 3#email.co ║
║ 19 ║ 2 ║ 3#email.co ║
║ 20 ║ 3 ║ 3#email.co ║
╚══════════╩════════════╩════════════╝
Now what I want to do, is that I want to select all brokers that have type 3 as the highest, most popular kind of house added. So for example if house type 3 represents "Apartments", I want to find the brokers that sell apartments as their number one most popular type.
My current query is:
SELECT b.id, b.email, h.email, h.type, h.total
FROM brokers b
INNER JOIN (
SELECT COUNT( * ) AS total, email, type
FROM house
GROUP BY email, type
ORDER BY total DESC
)h ON b.email = h.email
AND h.type = "3"
ORDER BY b.id DESC
Now this only selects the total amount of houses that that broker has for type 3. It does not only select the brokers where type 3 is their most popular type.
Now to do that, I need to use what is called "Groupwise Max". But I can not use max() on a count(*) like:
MAX(COUNT(*)) as max_value
So I guess that what I need to do is to nest my query further with additional subqueries to first count, and then select the max value.
I've been trying to get it right for a while now and I just can't get my head around it. Anyone can help?
EDIT:
Expected Output:
Based on the table above, Broker 1#email.co got:
1 House with Type 1.
2 Houses with Type 2.
4 Houses with Type 3.
Broker 2#email.co got:
2 houses with Type 1
2 houses with Type 2
1 house with Type 3.
Broker 3#email.co got:
1 house with Type 1.
3 houses with Type 2.
4 houses with Type 3.
Since both 1#email.co and 3#email.co is selling House Type 3 most commonly, they should be included in the output. 2#email.co do not sell type 3 as his most popular type, so he should not be included in the result.
So output:
╔══════════╦════════════╦════════════╦
║ ID ║ EMAIL ║ Total ║
╠══════════╬════════════╬════════════╬
║ 1 ║ 1#email.co ║ 4 ║
║ 3 ║ 3#email.co ║ 4 ║
╚══════════╩════════════╝════════════╝
Posting answer without executing, hope this works!
Select a.ID,a.Email,b.Cnt from Brokers as a
inner join (
Select Email,count(ID) as Cnt from Houses where Type =
(Select max(Type) from Houses)
group by Email
) as b on a.Email = b.Email
I can't understand why you need Count()? I think, according to you question ("select all brokers that have type 3") , it doesn't make sense, or do I misunderstand something?
EDIT:
I have done it in SQL SERVER by temporary table and variable
If you can convert it to mysql syntax, your problem will we solved:
SELECT COUNT(*) as total, Email, [Type]
into #tbl3
from house
group by Email, Type
declare #a int
set #a = (select MAX(total) from #tbl3)
SELECT b.id, b.email, h.email, h.type, h.total
FROM brokers b
inner join
(
select * from #tbl3
where total=#a
) h
on h.Email=b.Email and h.Type=3
EDIT: This is MySql syntax which will do your job.
CREATE TEMPORARY TABLE IF NOT EXISTS table2 AS (
SELECT COUNT(*) as total, Email, Type
from house
group by Email, Type
);
set #a = (select MAX(total) from table2);
SELECT b.id, b.email, h.email, h.type, h.total
FROM brokers b
inner join
(
select * from table2
where total=#a
) h
on h.Email=b.Email and h.Type=3

Update a table by inserting a count of foreign key from another table

I have two tables:
╔════════════════╗ ╔════════════════╗
║ ITEM ║ ║ ITEM_TRACK ║
╠════════════════╣ ╠════════════════╣
║ ID ║ ║ ID ║
║ GUID ║ ║ ITEM_GUID ║
║ COUNT1 ║ ║ CONTEXT ║
║ ENDDATE ║ ║ ║
╚════════════════╝ ╚════════════════╝
╔═════╦══════╦════════╗ ╔═════╦═══════════╦══════════╗
║ ID ║ GUID ║ COUNT1 ║ ║ ID ║ ITEM_GUID ║ CONTEXT ║
╠═════╬══════╬════════╣ ╠═════╬═══════════╬══════════╣
║ 1 ║ aaa ║ ║ ║ 1 ║ abc ║ ITEM ║
║ 2 ║ bbb ║ ║ ║ 2 ║ aaa ║ PAGE ║
║ 3 ║ ccc ║ ║ ║ 3 ║ bbb ║ ITEM ║
║ 4 ║ abc ║ ║ ║ 4 ║ ccc ║ ITEM ║
╚═════╩══════╩════════╝ ║ 5 ║ abc ║ ITEM ║
║ 6 ║ aaa ║ ITEM ║
║ 7 ║ abc ║ ITEM ║
║ 8 ║ ccc ║ PAGE ║
╚═════╩═══════════╩══════════╝
What I'm trying to do is fill in the COUNT1 column in ITEM with the count of the number of times ITEM_GUID appears in ITEM_TRACK for all ITEM.GUIDs where ENDDATE is still in the future. I need to do this once an hour for all GUIDS in ITEM.
I can get the counts I need easily
SELECT ITEM_GUID, COUNT(*) from ITEM_TRACK GROUP BY ITEM_GUID;
What I don't know how to do is, how do I merge this with an INSERT INTO statement to automatically update all the items in the items table with the count based on their ENDDATE?
UPDATE:
I have a working solution based on Aquillo's answer:
UPDATE ITEM a
SET COUNT1 = (SELECT COUNT(*) AS total FROM ITEM_TRACK b WHERE b.item_guid=a.guid);
Is there any other way to do this without a subquery?
You can insert from a select like this:
INSERT INTO myTable (foreignKey, countColumn) VALUES
SELECT ITEM_GUID, COUNT(*) from ITEM_TRACK GROUP BY ITEM_GUID;
In case you want to update, try something like this:
UPDATE from SELECT using SQL Server
If you use INSERT INTO you'll put additional rows in your ITEM table, not update the existing ones. If this is what you meant then that's great, but if you want to update the existing ones, you'll need to use update. You do this by joining the table you want to update with the table you want to update from. However, in your case you want to update from an aggregation and so you need to create a table with the aggregated values. Try this:
UPDATE ITEM SET Count1 = temp.total
FROM Item
INNER JOIN (
SELECT ITEM_GUID, COUNT(*) AS total
FROM ITEM_TRACK
GROUP BY ID) AS temp
ON Item.GUID = temp.ITEM_GUID
WHERE ENDDATE > NOW()
I've tried this on SQL Server (using GETDATE() instead of NOW()) to double check and it worked, I think it should work on MYSQL.

How to define target table in MySQL query?

how to fetch user name with user ID?
Suppose I have 3 tables like this and user.type holds 'e' for employer and 'w' for worker.
'e' says that user name is on employer.name and so 'w' says that user name is in worker.name.
employer.id and worker.id are foreign key of user.id.
Is there any way to get user name while having user id (we don't know type yet) with a single query?
Although if there's a problem with this kind of modeling let me know.
To answer your question directly,
SELECT a.*,
IF(a.type = 'e', b.Name, c.Name) PersonName
FROM User a
LEFT JOIN Employer b
ON a.ID = b.ID
LEFT JOIN Worker c
ON a.ID = c.ID
Actually, you can redesign the schema and needing only two tables, the Person and Type
Type
ID (PK)
TypeName
Person
ID (PK)
Name
UserTypeID (FK)
and you can easily get the type for every person,
SELECT a.*,
b.TypeName
FROM Person a
INNER JOIN Type b
ON a.UserTypeID = b.ID
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
SAMPLE RECORDS
TYPE
╔════╦══════════╗
║ ID ║ TYPENAME ║
╠════╬══════════╣
║ 1 ║ Employee ║
║ 2 ║ Worker ║
╚════╩══════════╝
PERSON
╔════╦═════════╦════════════╗
║ ID ║ NAME ║ USERTYPEID ║
╠════╬═════════╬════════════╣
║ 1 ║ Stacky ║ 2 ║
║ 2 ║ Horton ║ 1 ║
║ 3 ║ Alam Na ║ 1 ║
║ 4 ║ Aw aw ║ 2 ║
╚════╩═════════╩════════════╝
OUTPUT AFTER THE QUERY HAS BEEN EXECUTED
╔════╦═════════╦════════════╦══════════╗
║ ID ║ NAME ║ USERTYPEID ║ TYPENAME ║
╠════╬═════════╬════════════╬══════════╣
║ 1 ║ Stacky ║ 2 ║ Worker ║
║ 2 ║ Horton ║ 1 ║ Employee ║
║ 3 ║ Alam Na ║ 1 ║ Employee ║
║ 4 ║ Aw aw ║ 2 ║ Worker ║
╚════╩═════════╩════════════╩══════════╝

How do I write an SQL query where two columns need to be translated?

I've got two tables- one with records of stock, the other with translations (for French and German users).
Stock:
╔════╦═══════╦═══════════════════╦═══════════════════════════╗
║ ID ║ PRICE ║ ITEMTRANSLATIONID ║ ITEMCATEGORYTRANSLATIONID ║
╠════╬═══════╬═══════════════════╬═══════════════════════════╣
║ 1 ║ 10 ║ 423 ║ 1323 ║
║ 2 ║ 31 ║ 1776 ║ 1953 ║
╚════╩═══════╩═══════════════════╩═══════════════════════════╝
Translations:
╔══════╦═══════════╦════════════╦═════════╗
║ ID ║ ENGLISH ║ FRENCH ║ GERMAN ║
╠══════╬═══════════╬════════════╬═════════╣
║ 1 ║ knife ║ couteau ║ messer ║
║ 2 ║ fork ║ fourchette ║ gabel ║
║ 423 ║ spoon ║ cuillère ║ löffel ║
║ 1323 ║ cultery ║ couverts ║ besteck ║
║ 1776 ║ table ║ table ║ tabelle ║
║ 1953 ║ furniture ║ meubles ║ möbel ║
╚══════╩═══════════╩════════════╩═════════╝
Is there a way to write an SQL query to get prices and translated names for each stock item? I will only ever need one language at once.
If only one column needed translating, I could just use an INNER JOIN. The trouble is, there are two columns that need translating- one for the item name, the other for the item category name.
i.e.
Required Output (French)
╔════╦═══════╦══════════╦══════════════╗
║ ID ║ PRICE ║ ITEM ║ ITEMCATEGORY ║
╠════╬═══════╬══════════╬══════════════╣
║ 1 ║ 10 ║ cuillère ║ couverts ║
║ 2 ║ 31 ║ table ║ meubles ║
╚════╩═══════╩══════════╩══════════════╝
join table Translations twice on table Stock so you could get the values for each columns in table Stock
SELECT a.ID, a.Price, b.French AS Item, c.French AS ItemCategory
FROM Stock a
INNER JOIN Translations b
ON a.ItemTranslationId = b.ID
INNER JOIN Translations c
ON a.ItemCategoryTranslationId = c.ID
SQLFiddle Demo
With this table structure, you would need to JOIN to the Translations table twice... once to get the Item, and again to get the ItemCategory:
SELECT
s.ID,
s.Price,
i.French AS Item,
ic.French AS ItemCategory
FROM
Stock s
JOIN Translations i ON i.ID = s.ItemTranslationId
JOIN Translations ic ON ic.ID = s.ItemCategoryTranslationId
You can use this query:
SELECT a.ID, a.Price,
(select French from Translations b where b.ID=a.ItemTranslationId) as ITEM,
(select French from Translations c where c.ID=a.ItemCategoryTranslationId) as ITEMCATEGORY
FROM Stock a