SQL: Detect multiple same entries as a batch - mysql

The use-case is a follows. When I have multiple entries with same content, the results should be somehow clubbed together depending on the exact data except some important key.
------------------------------------
| student_id | subject_id | marks |
------------------------------------
| STD001 | SUB001 | 10 |
| STD001 | SUB002 | 20 |
| STD002 | SUB001 | 10 |
| STD002 | SUB002 | 20 |
| STD003 | SUB001 | 11 |
| STD003 | SUB002 | 20 |
| STD004 | SUB001 | 11 |
| STD004 | SUB002 | 20 |
| STD005 | SUB001 | 11 |
| STD005 | SUB002 | 20 |
| STD005 | SUB003 | 30 |
------------------------------------
Expected final result
-------------------------------------------------
| subject_id_str | marks_str | student_id |
-------------------------------------------------
| SUB001_SUB002 | 10_20 | STD001 |
| SUB001_SUB002 | 10_20 | STD002 |
| SUB001_SUB002 | 11_20 | STD003 |
| SUB001_SUB002 | 11_20 | STD004 |
| SUB001_SUB002_SUB003 | 11_20_30 | STD005 |
-------------------------------------------------
OR
--------------------------------------------------------
| subject_id_str | marks_str | student_id_str |
--------------------------------------------------------
| SUB001_SUB002 | 10_20 | STD001_STD002 |
| SUB001_SUB002 | 11_20 | STD003_STD004 |
| SUB001_SUB002_SUB003 | 11_20_30 | STD005 |
--------------------------------------------------------
More Info: Using MySQL 5.7

You can use string aggregation:
select
group_concat(subject_id order by subject_id separator '_') as subject_id_str,
group_concat(marks order by subject_id separator '_') as marks_str,
student_id
from mytable
group by student_id

Related

how to sort sql data for given table?

+---------+----------------+--------+
| aid | fn | col_no |
+---------+----------------+--------+
| 2011768 | ABDUL | 5 |
| 2011499 | ABDULLA | 4 |
| 2011198 | ADNAN | 3 |
| 2011590 | AKSHAYA PRAISY | 2 |
| 2011749 | AMIR | 1 |
| 2011213 | AMOGHA | 5 |
| 2011027 | ANU | 4 |
| 2011046 | ANUDEV D | 3 |
| 2011435 | B S SAHANA | 2 |
| 2011112 | BENAKA | 1 |
+---------+----------------+--------+
How to sort the number like col_no as 1 2 3 4 5 and again repeat as 1 2 3 4 5?
i need output like this
+---------+----------------+--------+
| aid | fn | col_no |
+---------+----------------+--------+
| 2011749 | AMIR | 1 |
| 2011590 | AKSHAYA PRAISY | 2 |
| 2011198 | ADNAN | 3 |
| 2011499 | ABDULLA | 4 |
| 2011768 | ABDUL | 5 |
| 2011112 | BENAKA | 1 |
| 2011435 | B S SAHANA | 2 |
| 2011046 | ANUDEV D | 3 |
| 2011027 | ANU | 4 |
| 2011213 | AMOGHA | 5 |
+---------+----------------+--------+
You can use row_number() partition by col_no:
select t.*
from t
order by row_number() over (partition by col_no order by fn),
col_no;
Here is a db<>fiddle.

Selecting only the latest version in a group with a specific status [duplicate]

This question already has answers here:
MySQL Select Latest Row of Specific Value
(2 answers)
Closed 2 years ago.
In a project I am working on I have the table you can see below. On the frontend I need to show only the records that are published grouped by the entity_id. For example, in the example below only id 1, 11, 16 and 19 should be shown. I have no idea how to make this query. I tried several things with subqueries etc but none of them work. I guess there should be a way to retrieve this data. What am I missing?
| id | revision | entity_id | status
========================================
| 1 | 1 | 1 | published
| 2 | 2 | 1 | archived
| 3 | 1 | 2 | draft
| 4 | 2 | 2 | draft
| 5 | 3 | 2 | draft
| 6 | 4 | 2 | ready
| 7 | 5 | 2 | draft
| 8 | 6 | 2 | published
| 9 | 7 | 2 | published
| 10 | 8 | 2 | ready
| 11 | 9 | 2 | published
| 13 | 1 | 3 | draft
| 14 | 1 | 4 | draft
| 15 | 2 | 4 | draft
| 16 | 3 | 4 | published
| 18 | 1 | 5 | draft
| 19 | 2 | 5 | published
| 20 | 3 | 5 | draft
| 21 | 10 | 5 | archived
I created a DBFiddle to play around:
https://www.db-fiddle.com/f/4UcjKhTvzzNQWL3Pfkfew4/1
Note It's not the same as SQL select only rows with max value on a column since the answer there would select all the revisions that are published and not just the latest one.
Presumably you're after something like this...
DROP TABLE IF EXISTS entities;
CREATE TABLE `entities`
( id SERIAL PRIMARY KEY
, entity_id INT NOT NULL
, revision INT NOT NULL DEFAULT '1'
, type enum('gym','trainer')
, status enum('published','ready','draft','archived') NOT NULL DEFAULT 'draft'
, UNIQUE KEY entities_entity_id_revision_unique (entity_id,revision)
);
INSERT INTO entities
(id, entity_id, revision, type,status) VALUES
( 1,1, 1,'gym','published'),
( 2,1, 2,'gym','archived'),
( 3,2, 1,'gym','draft'),
( 4,2, 2,'gym','draft'),
( 5,2, 3,'gym','draft'),
( 6,2, 4,'gym','ready'),
( 7,2, 5,'gym','draft'),
( 8,2, 6,'gym','published'),
( 9,2, 7,'gym','published'),
(10,2, 8,'gym','ready'),
(11,2, 9,'gym','published'),
(13,3, 1,'gym','draft'),
(14,4, 1,'gym','draft'),
(15,4, 2,'gym','draft'),
(16,4, 3,'gym','published'),
(18,5, 1,'gym','draft'),
(19,5, 2,'gym','draft'),
(20,5, 3,'gym','draft'),
(21,5,10,'gym','published');
SELECT x.*
FROM entities x
JOIN
( SELECT entity_id
, MAX(revision) revision
FROM entities
WHERE status = 'published'
GROUP
BY entity_id
) y
ON y.entity_id = x.entity_id
AND y.revision = x.revision;
+----+-----------+----------+------+-----------+
| id | entity_id | revision | type | status |
+----+-----------+----------+------+-----------+
| 1 | 1 | 1 | gym | published |
| 11 | 2 | 9 | gym | published |
| 16 | 4 | 3 | gym | published |
| 21 | 5 | 10 | gym | published |
+----+-----------+----------+------+-----------+
4 rows in set (0.00 sec)
You can also use over partition by.
SELECT * FROM(
SELECT *,
ROW_NUMBER() OVER( PARTITION BY ENTITY_ID ORDER BY REVISION ASC) AS RN
FROM ENTITIES
WHERE STATUS = 'PUBLISHED') K WHERE RN =1
| id | entity_id | revision | type | status | name | slug | short_description | description | address | phone | email | website | openinghours | images | thumbnail | pricerange | created_at | updated_at | deleted_at | RN |
| --- | --------- | -------- | ---- | --------- | ---- | ---- | ----------------- | ----------- | ------- | ----- | ----- | ------- | ------------ | ------ | --------- | ---------- | ------------------- | ------------------- | ------------------- | --- |
| 1 | 1 | 1 | gym | published | | | | | | | | | | | | | 2020-10-03 21:49:14 | 2020-10-03 21:49:14 | | 1 |
| 8 | 2 | 6 | gym | published | | | | | | | | | | | | | 2020-10-10 16:28:14 | 2020-10-10 16:28:15 | | 1 |
| 16 | 4 | 3 | gym | published | | | | | | | | | | | | | 2020-10-10 17:06:38 | 2020-10-10 17:06:53 | 2020-10-10 17:06:53 | 1 |
| 21 | 5 | 10 | gym | published | | | | | | | | | | | | | 2020-10-11 14:54:16 | 2020-10-11 14:54:16 | | 1 |
View on DB Fiddle
It s almost the same as with the max value
Query #1
SELECT *
FROM
`entities`
WHERE id IN
(SELECT MIN(id)id FROM
`entities`
WHERE `status` = 'published'
GROUP BY `entity_id`);
| id | entity_id | revision | type | status | name | slug | short_description | description | address | phone | email | website | openinghours | images | thumbnail | pricerange | created_at | updated_at | deleted_at |
| --- | --------- | -------- | ---- | --------- | ---- | ---- | ----------------- | ----------- | ------- | ----- | ----- | ------- | ------------ | ------ | --------- | ---------- | ------------------- | ------------------- | ------------------- |
| 1 | 1 | 1 | gym | published | | | | | | | | | | | | | 2020-10-03 21:49:14 | 2020-10-03 21:49:14 | |
| 8 | 2 | 6 | gym | published | | | | | | | | | | | | | 2020-10-10 16:28:14 | 2020-10-10 16:28:15 | |
| 16 | 4 | 3 | gym | published | | | | | | | | | | | | | 2020-10-10 17:06:38 | 2020-10-10 17:06:53 | 2020-10-10 17:06:53 |
| 21 | 5 | 10 | gym | published | | | | | | | | | | | | | 2020-10-11 14:54:16 | 2020-10-11 14:54:16 | |
View on DB Fiddle
If you have multiple rivision you can use max, as the id is always increase by every new revision this makes no difference at all
Query #1
SELECT *
FROM
`entities`
WHERE (`entity_id` ,`revision`) IN
(SELECT `entity_id` ,MAX(`revision`) FROM
`entities`
WHERE `status` = 'published'
GROUP BY `entity_id`);
| id | entity_id | revision | type | status | name | slug | short_description | description | address | phone | email | website | openinghours | images | thumbnail | pricerange | created_at | updated_at | deleted_at |
| --- | --------- | -------- | ---- | --------- | ---- | ---- | ----------------- | ----------- | ------- | ----- | ----- | ------- | ------------ | ------ | --------- | ---------- | ------------------- | ------------------- | ------------------- |
| 1 | 1 | 1 | gym | published | | | | | | | | | | | | | 2020-10-03 21:49:14 | 2020-10-03 21:49:14 | |
| 11 | 2 | 9 | gym | published | | | | | | | | | | | | | 2020-10-10 16:48:20 | 2020-10-10 17:00:47 | |
| 16 | 4 | 3 | gym | published | | | | | | | | | | | | | 2020-10-10 17:06:38 | 2020-10-10 17:06:53 | 2020-10-10 17:06:53 |
| 21 | 5 | 10 | gym | published | | | | | | | | | | | | | 2020-10-11 14:54:16 | 2020-10-11 14:54:16 | |
View on DB Fiddle

Join two tables on nearest matching string

I have a query_table Table and wants to join with match_table Table with nearest matching string. If it was vice-versa then 'like' would have worked but have no idea how to do this.
query_table
+----+------------------+
| id | string |
+----+------------------+
| 1 | fcc9e8796feb |
| 2 | fcdbd7ebcf89 |
| 3 | fccc87896feb |
| 4 | fcc7c7896fef |
| 5 | fcced777aaaf |
+----+------------------+
match_table
+----+-----------+
| id | match_code|
+----+-----------+
| 1 | fcff |
| 2 | fcccc |
| 3 | fccc8 |
| 4 | fccc9 |
| 5 | fccdb |
| 6 | fccdc |
| 7 | fccd8 |
| 8 | fcce |
| 9 | fcced |
| 10 | fccee |
| 11 | fcce6 |
| 12 | fcc7b |
| 13 | fcc7c |
| 14 | fcc8e |
| 15 | fcc87 |
| 16 | fcc88 |
| 17 | fcc9e |
| 18 | fcdbb |
| 19 | fcdbc |
| 20 | fcdbd |
+----+-----------+
I expect
result
+----+------------------+----+----------------+
| id | string | id | match_code |
+----+------------------+----+----------------
| 1 | fcc9e8796feb | 17 | fcc9e |
| 2 | fcdbd7ebcf89 | 20 | fcdbd |
| 3 | fccc87896feb | 3 | fccc8 |
| 4 | fcc7c7896fef | 13 | fcc7c |
| 5 | fcced777aaaf | 9 | fcced |
+----+------------------+----+----------------+

MYSQL can't load character into set

I have this file:
1.nothing
2.o,s,f,d
3.f,d
4.o,s
5.s,f,d
6.s
7.nothing
8.s,f,d
9.o,d
10.s,f
And a table:
describe delete_me;
+------------+----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| privileges | set('o','s','f','d') | YES | | NULL | |
+------------+----------------------+------+-----+---------+-------+
When I try to:
LOAD DATA INFILE 'privileges.txt' INTO TABLE delete_me FIELDS TERMINATED BY '.';
I get this:
+------+------------+
| id | privileges |
+------+------------+
| 0 | |
| 2 | f,s,o |
| 3 | f |
| 4 | o |
| 5 | f,s |
| 6 | |
| 7 | |
| 8 | f,s |
| 9 | o |
| 10 | s |
| 11 | o |
| 12 | |
| 13 | o |
| 14 | o |
| 15 | s |
| 16 | |
| 17 | o |
| 18 | o |
| 19 | s,o |
| 20 | f |
+------+------------+
The letter d just disappears. Why?

Populating a column by extracting a value from other column in the same table

I have a table callInfo and it looks like this:
+----+------------------------------------------------------------------------------------------------------------------------------------+
| id | idUrl | collectionId | |
+----+------------------------------------------------------------------------------------------------------------------------------------+
| 1 | id?books.0.levelOfDetail=high&books.0.shopId=727&books.0.type=books&collectionId=20092014&type=seasonPassSource | |
| 2 | id:call3?books.0.levelOfDetail=high&books.0.shopId=123&books.0.type=books&collectionId=16645&type=seasonPassSource | |
| 3 | id:call3?maxDepth=1&parentMixId=777&type=mixSource | |
| 4 | idSet:call3?keyword=%22FOO%20BAR%20.%5E%24*%2B%3F%7C%28%29%7B%7D%5B%5D%22&type=wishListSource | |
| 5 | idSet:call3?books.0.levelOfDetail=high&books.0.shopId=727 | |
| 6 | idSetSource.0.booksNumber=2&collectionId=16645&books.0.levelOfDetail=high&books.0.type=books&type=seasonPassSource | |
| 7 | idSet:call3?keyword=hero&type=wishListSource | |
+----+-------------------------+----------------------------------------------------------------------------------------------------------+
I have created a new column called collectionId in the table callInfo, but the are many records in the table for which I need to update this column value.
I need to extract the value of collectionId from idUrl column and put it in collectionId column.
it should look like this
+----+------------------------------------------------------------------------------------------------------------------------------------+
| id | idUrl | collectionId | |
+----+------------------------------------------------------------------------------------------------------------------------------------+
| 1 | id?books.0.levelOfDetail=high&books.0.shopId=727&books.0.type=books&collectionId=20092014&type=seasonPassSource | 20092014 |
| 2 | id:call3?books.0.levelOfDetail=high&books.0.shopId=123&books.0.type=books&collectionId=16645&type=seasonPassSource | 16645 |
| 3 | id:call3?maxDepth=1&parentMixId=777&type=mixSource | NULL |
| 4 | idSet:call3?keyword=%22FOO%20BAR%20.%5E%24*%2B%3F%7C%28%29%7B%7D%5B%5D%22&type=wishListSource | NULL |
| 5 | idSet:call3?books.0.levelOfDetail=high&books.0.shopId=727 | NULL |
| 6 | idSetSource.0.booksNumber=2&collectionId=16645&books.0.levelOfDetail=high&books.0.type=books&type=seasonPassSource | 16645 |
| 7 | idSet:call3?keyword=hero&type=wishListSource | NULL |
+----+-------------------------+----------------------------------------------------------------------------------------------------------+
I need to do this in MySQL. Any ideas?
Another way to do it using SUBSTRING_INDEX()
UPDATE callInfo
SET collectionId = SUBSTRING_INDEX(SUBSTR(idUrl, INSTR(idUrl, 'collectionId=') + 13), '&', 1)
WHERE idUrl LIKE '%collectionId=%'
Output:
| ID | ... | COLLECTIONID |
|----| ... |--------------|
| 1 | ... | 20092014 |
| 2 | ... | 16645 |
| 3 | ... | (null) |
| 4 | ... | (null) |
| 5 | ... | (null) |
| 6 | ... | 16645 |
| 7 | ... | (null) |
Here is SQLFiddle demo