Dedup rows of a mirrored column using SQL - mysql

In MySQL, assuming I have a table with First Name and Last Name,
FName - LName
John - Paul
Paul - John
Alice - Peter
Peter - Alice
So if you see every row will have duplicate entry but in reverse.
I would like to select the rows in such a way that only one of the rows is selected for each unique entry (Doesn't matter which one).
My resulting table should be like:
FName - LName
John - Paul
Peter - Alice
There is more than one correct result, but I hope you got the point.
Thanks in advance!

SELECT DISTINCT
least(fName, lName) fName,
greatest (FName, lName) lName
FROM table
This will do it. Your first names will come before the associated last names in the collatino.

Try the following, assuming there are always 2 duplicates, no more, no less:
This assumes your table has one column with the 2 values separated by a hyphen.
Fiddle: http://sqlfiddle.com/#!2/c04fae/2/0
select
min(col_lr) as de_duplicated
from
(
select
x.col as col_lr,
count(y.col) + count(z.col) as grp
from
tbl x
left join tbl y on x.col < y.col
left join tbl z on concat(right(x.col, length(x.col) - locate(' - ', x.col) - 2), ' - ', substr(x.col, 1, locate(' - ', x.col) - 1)) < z.col
group by
x.col
) x
group by
grp
It establishes a composite rank in ABC order (for both left to right, and right to left) within the table, giving that group value the same for both duplicated rows, at which point you can just select the first of the two.

Related

SQL compose bi-gram and search if exists in other table

In SQL, having a table T1 contains
TITLE
age 5 alton john live
show must go on
Having a table T2 contains
NAME.
DESCRIPTION
John Bo
altonjohn for kids
Alton
show age5 mustgo kids
I would like to finding bigrams (pairs of consecutive words) in TITLE (T1) and check if at list 1 bigram exists in DESCRIPTION (T2) and return TITLE, DESCRIPTION & the BI-GRAM
Expected Output:
TITLE
DESCRIPTION
. BIGRAM
age 5 alton john live.
altonjohn for kids.
. altonjohn
age 5 alton john live.
show age5 mustgo kids
. age5
show must go on
show age5 mustgo kids
. mustgo
A slight variation of the previous query should do this easily:
WITH RECURSIVE cte AS (
SELECT TITLE,
LENGTH(TITLE)-LENGTH(REPLACE(TITLE,' ','')) AS num_bigrams,
SUBSTRING_INDEX(
SUBSTRING_INDEX(TITLE, ' ',
LENGTH(TITLE)-LENGTH(REPLACE(TITLE,' ',''))+1
), ' ', -2) AS bigram
FROM t1
UNION ALL
SELECT TITLE,
num_bigrams - 1 AS num_bigrams,
SUBSTRING_INDEX(SUBSTRING_INDEX(TITLE, ' ', num_bigrams), ' ', -2)
FROM cte
WHERE num_bigrams > 1
)
SELECT TITLE, DESCRIPTION, bigram
FROM cte
INNER JOIN t2
ON t2.DESCRIPTION REGEXP CONCAT('( |^)', cte.bigram, '( |$)')
Differences are:
Using -2 in the SUBSTRING_INDEX function, to recover the last two words instead of the last one [you can generalize on this for trigrams and others too], both for the base and the recursive step of the recursion.
Getting the recursion to end 1 step earlier, cause bigrams will take 2 words at a time, hence changing the recursion ending condition to WHERE num_bigrams > 1 instead of WHERE num_bigrams > 0.
Check the demo here.
Note: if you want to remove the middle space from the bigram, you just need to add a REPLACE function that removes that extra space.

counting comma separated values mysql-postgre

I have a column called "feedback", and have 1 field called "emotions". In those emotions field, we can see the random values and random length like
emotions
sad, happy
happy, angry, boring
boring
sad, happy, boring, laugh
etc with different values and different length.
so, the question is, what's query to serve the mysql or postgre data:
emotion
count
happy
3
angry
1
sad
2
boring
3
laugh
1
based on SQL: Count of items in comma-separated column in a table we could try using
SELECT value as [Holiday], COUNT(*) AS [Count]
FROM OhLog
CROSS APPLY STRING_SPLIT([Holidays], ',')
GROUP BY value
but it wont help because that is for sql server, not mysql or postgre. or anyone have idea to translation those sqlserver query to mysql?
thank you so much.. I really appreciate it
Using Postgres:
create table emotions(id integer, emotions varchar);
insert into emotions values (1, 'sad, happy');
insert into emotions values (2, 'happy, angry, boring');
insert into emotions values (3, 'boring');
insert into emotions values (4, 'sad, happy, boring, laugh');
select
emotion, count(*)
from
(select
trim(regexp_split_to_table(emotions, ',')) as emotion
from emotions) as t
group by
emotion;
emotion | count
---------+-------
happy | 3
sad | 2
boring | 3
laugh | 1
angry | 1
From String functions regexp_split_to_table will split the string on ',' and return the individual elements as rows. Since there are spaces between the ',' and the word use trim to get rid of the spaces. This then generates a 'table' that is used as a sub-query. In the outer query group by the emotion field and count them.
Try the following using MySQL 8.0:
WITH recursive numbers AS
(
select 1 as n
union all
select n + 1 from numbers where n < 100
)
,
Counts as (
select trim(substring_index(substring_index(emotions, ',', n),',',-1)) as emotions
from Emotions
join numbers
on char_length(emotions) - char_length(replace(emotions, ',', '')) >= n - 1
)
select emotions,count(emotions) as counts from Counts
group by emotions
order by emotions
See a demo from db-fiddle.
The recursive query is to generate numbers from 1 to 100, supposing that the maximum number of sub-strings is 100, you may change this number accordingly.
I've used MySQL 8.0, the query has no string limits. (Thanks to Ahmed for the intuition on recursive clause)
WITH RECURSIVE cte AS (
SELECT ( LENGTH(REGEXP_REPLACE(emotions, ' ?[A-z]+ ?', ''))+1) AS n, emotions AS subs
FROM feedback
UNION ALL
SELECT n-1 AS n, ( SUBSTRING_INDEX(subs, ', ', n-1) ) AS subs
FROM cte
HAVING n>0
)
SELECT SUBSTRING_INDEX(subs, ', ', -1) AS emotions, COUNT(subs) AS cnt
FROM cte
GROUP BY emotions

MySQL - How can I group music together when the names are similar?

I would like to be able to return a single line when the name of some musics are the same or similar, as for example this case:
music with similar names
You can see that the names are the same with an extension like " - JP Ver." or something like that, I would like to be able to group them in one row with the first column incrementing the whole.
My current request to return these lines is as follows:
select count(id) number, name, sec_to_time(floor(sum(duration) / 1000)) time
from track
where user_id = 'value'
group by name, duration
order by number desc, time desc;
I would like to get a result like this
Thank you for reading and responding! I wish you all a good day!
Try:
SELECT COUNT(name) no,
TRIM(SUBSTRING_INDEX(name, '-', 1)) namee
FROM track
GROUP BY namee
Example: https://onecompiler.com/mysql/3xt3bfev6
Use GROUP_CONCAT
Here is a proof of concept script. You can add your other columns. I have grouped by the first 4 letters. You will probably want to use more.
CREATE TABLE track (
idd INT,
nam CHAR(50),
tim INT
);
INSERT INTO track VALUES (1,'Abba 1',5);
INSERT INTO track VALUES (2,'Abba 2',6);
INSERT INTO track VALUES (3,'Beta 1',12);
INSERT INTO track VALUES (4,'Beta 4',8);
SELECT
LEFT(nam,4) AS 'Group',
COUNT(idd) AS 'Number',
GROUP_CONCAT(DISTINCT idd ORDER BY idd ASC SEPARATOR ' & ') AS IDs,
GROUP_CONCAT(DISTINCT nam ORDER BY nam ASC SEPARATOR ', ') AS 'track names',
SUM(tim) AS 'total time'
FROM track
GROUP BY LEFT(nam,4);
DROP TABLE track;
Output
Group Number IDs track names total time
Abba 2 1 & 2 Abba 1, Abba 2 11
Beta 2 3 & 4 Beta 1, Beta 4 20

(SQL) Get comma separated specific value total count

I need to get the total number of occurrences by separate server ID like below :
-----------------------------
logID serversID
-------------------------------
1 50,51,51,50
2 51,52
3 50,50
I want a result like this:
ServerID Count
------------ ---------------
50 4
51 3
52 1
Thanks you for your help.
Fix your data model! A string is the wrong way to store multiple values. A string is the wrong way to store numbers. The correct way to represent this data is to use a second table, with one row per logid and serverid.
If you are stuck with this data model and you don't have a reference table for servers, you can split the values . . . painfully:
select substring_index(substring_index(t.serversid, ',', n.n), ',', -1) as server, count(*)
from (select 1 as n union all
select 2 union all
select 3 union all
. . . -- as many as the biggest list
) n join
t
on t.servers like concat(repeat('%,', n.n - 1), '%')
group by server;
Here is a db<>fiddle.

How count the number of rows starting from a specified row?

I have a query problem about retrieving number of rows that the counting will start from the specified row. These are the row values on my MySQL database.
John Parker
Tony Graham
Perter Smith
Annabelle Sergio
Kris Pata
Neshren Luca
Paul Pon
Zervich Nuckrav
Allan Paulson
Imanu Hashmarida
Varick Dagovich
Senster Burgsman
Lito Umani
Ramsay Nudillo
Now I want to retrieve the first 5 row that will start from Neshren Luca so that the resultset may look like this:
Neshren Luca
Paul Pon
Zervich Nuckrav
Allan Paulson
Imanu Hashmarida
How may I do that?
Note: I will not try to retrieve the row values base on number of row but base from a specific row value.
This looks very ugly but have this a try, this uses local variable
SET #selectedName := 'Neshren Luca'; -- set the name here
SET #selectRow :=
(
SELECT RankNo
FROM
(
SELECT #rowNum := #rowNum + 1 AS RankNo,
a.Names
FROM tableName a, (SELECT #rowNum:= 0) b
) x
WHERE Names = #selectedName
);
SELECT Names
FROM
(
SELECT #rowNum1 := #rowNum1 + 1 AS RankNo, a.Names
FROM tableName a, (SELECT #rowNum1:= 0) b
) x
WHERE RankNo BETWEEN #selectRow AND #selectRow + 4
SQLFiddle Demo
Looks like the above select statement will work fine for that..other wise you have to do other way but it will bit lengthy..that..
-> You have to get the above records into a cursor
-> Looping through the cursor and getting the records..
SQL engine may have some 'natural' row order, but it is not guaranteed. You should have primary key, say ID, then ORDER BY ID, find first ID WHERE your string is. And then select first N items WHERE ID >= that id.
Edit: Or, if your database guarantees natural order, find row id/index and LIMIT/OFFSET by this value. SQLite has built-in natural rowid for each table row, for example.