Select Parent node in nested data set - mysql

Have teh follwoing query which is fine and dandy...
SELECT
`node`.`site_pages_id` AS `page_id` ,
GROUP_CONCAT(`parent`.`site_pages_id` SEPARATOR '/') AS `path` ,
IFNULL( CONCAT( '/' , GROUP_CONCAT(`parent`.`url` SEPARATOR '/') ) , '/' ) AS `url`
FROM
`site_pages` AS `node`
LEFT JOIN
`site_pages` AS `parent`
ON
`node`.`lft_limit` BETWEEN `parent`.`lft_limit` AND `parent`.`rgt_limit`
GROUP BY
`node`.`site_pages_id`
ORDER BY
`node`.`lft_limit` ASC
produces the following
1, 1, /
2, 1/2, /about-us
8, 1/2/8, /about-us/meet-the-team
3, 1/3, /web
5, 1/5, /print
6, 1/6, /branding
7, 1/7, /contact-us
All sweet.
I'd like to select the immediate parent and just the immediate parent for each node.
My feeble attempts at doing so without a nasty subquery fail misearably (not much better with TBO).
Tips muchly appreciated

No probs Martin...
page_id url lft_limit rgt_limit
1, NULL, 1, 14,
2, about-us, 2, 5,
3, web, 6, 7,
5, print, 8, 9,
6, branding, 10, 11,
7, contact-us, 12, 13,
8, meet-the-team, 3, 4,

Related

Query for array elements inside Jsonb type postgreSQL

I have a psql table where one of the jsonb data is extracted over it.
{
"SrcRcs": [4, 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 158],
"reason": "",
"result": "Success",
"InitTech": 1
}
This column is named Data and is of type jsonb.
I am extracting the SrcRcs data from the jsonb:
select Data->'SrcRcs' from table_name;
Output:
[4, 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 158]
But which is in unsorted order as from the jsonb.
I want it in the sorted order like this:
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,158]
Can someone please help me out?
I have tried the psql sort() but wasn't able to achieve the desired result.
You need to unnest the array elements and then aggregate them back in a sorted way:
SELECT (select jsonb_agg(i::int order by i::int)
from jsonb_array_elements(data -> 'SrcRcs') as t(i))
from the_table
If you want, you can create a function for this to make the SQL queries easier.

Finding Connection Pairs

Suppose we have a table in mySQL database where fname has a connection to another fname(BB_Connection_name), we would like have a query to find the pair(s) of friends who find connection among themselves.
E.g
Sidharth and Asim both have each others BBid and BB_Connection_ID
I have looked for similar case of father, son and grandson question but in that not each father has a son and thus inner joining them makes things easier for solving. I tried using that but didn't work.
Here i need to check BB_Connection_ID for every fname(A) and then corresponding fname has A's BBid as his BB_Connection_ID or not.
The pairs which would be chosen, should be like Sidharth<->Asim
We need to find the pairs who have their connection ID to each other.
==========================================================================
Code for recreation of the table:
-----------------------------------------------------------------------------
create table world.bigbb(
BBid int not null auto_increment,
fname varchar(20) NOT NULL,
lname varchar(30),
BBdays int not null,
No_of_Nom int,
BB_rank int not null,
BB_Task varchar(10),
BB_Connection_ID int,
BB_Connection_name varchar(10),
primary key (BBid)
);
insert into world.bigbb (fname, lname, BBdays, No_of_Nom, BB_rank, BB_Task, BB_Connection_ID, BB_Connection_name)
values
('Sidharth', 'Shukla', 40, 4, 2, 'Kitchen', 11, 'Asim'),
('Arhaan', 'Khan', 7, 1, 9, 'Kitchen', 16, 'Rashmi'),
('Vikas', 'Bhau', 7, 1, 8, 'Bedroom', 11, 'Asim'),
('Khesari', 'Bihari', 7, 1, 12, 'Kitchen', 9, 'Paras'),
('Tehseem', 'Poonawala', 7, 1, 11, 'Washroom', 12, 'Khesari'),
('Shehnaaz', 'Gill', 40, 4, 4, 'Washroom', 9, 'Paras'),
('Himanshi', 'Khurana', 7, 0, 7, 'Bedroom', 8, 'Shefali'),
('Shefali', 'Zariwala', 7, 1, 10, 'Bedroom', 1, 'Sidharth'),
('Paras', 'Chabra', 40, 3, 1, 'Bathroom', 10, 'Mahira'),
('Mahira', 'Sharma', 40, 4, 5, 'Kitchen', 9, 'Paras'),
('Asim', 'Khan', 40, 3, 3, 'Bathroom', 1, 'Sidharth'),
('Arti', 'Singh', 40, 5, 6, 'Captain', 1, 'Sidharth'),
('Sidharth', 'Dey', 35, 6, 16, 'None', 14, 'Shefali'),
('Shefali', 'Bagga', 38, 5, 15, 'None', 13, 'Sidharth'),
('Abu', 'Fifi', 22, 5, 17, 'None', 11, 'Asim'),
('Rashmi', 'Desai', 38, 5, 13, 'None', 17, 'Debolina'),
('Debolina', 'Bhattacharjee', 38, 5, 14, 'None', 16, 'Rashmi');
One solution would be to self-join the table:
select
b1.fname name1,
b2.fname name2
from bigbb b1
inner join bigbb b2
on b1.BB_Connection_ID = b2.BBid
and b2.BB_Connection_ID = b1.BBid
and b1.BBid < b2.BBid
This will give you one record for each pair, with the record having the smallest BBid in the first column.
This demo on DB Fiddle with your sample data returns:
name1 | name2
:------- | :-------
Sidharth | Asim
Paras | Mahira
Sidharth | Shefali
Rashmi | Debolina

How to format uuid string from binary column in MySQL/MariaDB

In MySQL/MariaDB the most efficient way to store uuid is in a BINARY(16) column. However, sometimes you want to obtain it as a formatted uuid string.
Given the following table structure, how would I obtain all uuids in a default formatted way?
CREATE TABLE foo (uuid BINARY(16));
The following would create the result I was after:
SELECT
LOWER(CONCAT(
SUBSTR(HEX(uuid), 1, 8), '-',
SUBSTR(HEX(uuid), 9, 4), '-',
SUBSTR(HEX(uuid), 13, 4), '-',
SUBSTR(HEX(uuid), 17, 4), '-',
SUBSTR(HEX(uuid), 21)
))
FROM foo;
MySQL 8 adds two new UUID functions:
UUID_TO_BIN
BIN_TO_UUID - this is the one you're looking for
So:
SELECT BIN_TO_UUID(uuid) FROM foo
In earlier (prior to 8) versions you can create a function in MySQL like the following:
CREATE
FUNCTION uuid_of(uuid BINARY(16))
RETURNS VARCHAR(36)
RETURN LOWER(CONCAT(
SUBSTR(HEX(uuid), 1, 8), '-',
SUBSTR(HEX(uuid), 9, 4), '-',
SUBSTR(HEX(uuid), 13, 4), '-',
SUBSTR(HEX(uuid), 17, 4), '-',
SUBSTR(HEX(uuid), 21)
));
And then simply use it in your queries:
SELECT
uuid_of(id)
name,
age
FROM users
And it produces:
(c6f5703b-fec2-43fd-8f45-45f06583d450, Some name, 20)
If you are looking for the opposite, i.e., how to convert from string to binary, perhaps to do a join or something, this is covered here : Convert UUID to/from binary in Node
This piece of SQL run on Mysql 5.7 helped lock in the concept for me:
SELECT
LOWER(CONCAT(
SUBSTR(HEX(UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', ''))), 1, 8), '-',
SUBSTR(HEX(UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', ''))), 9, 4), '-',
SUBSTR(HEX(UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', ''))), 13, 4), '-',
SUBSTR(HEX(UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', ''))), 17, 4), '-',
SUBSTR(HEX(UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', ''))), 21)
))
The output is 43d597d7-2323-325a-90fc-21fa5947b9f3.
string -> binary
So UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', '')) to convert a UUID to binary during an INSERT / UPDATE / JOIN / SELECT whatever, and
binary -> string
LOWER(CONCAT(
SUBSTR(HEX(uuid), 1, 8), '-',
SUBSTR(HEX(uuid), 9, 4), '-',
SUBSTR(HEX(uuid), 13, 4), '-',
SUBSTR(HEX(uuid), 17, 4), '-',
SUBSTR(HEX(uuid), 21)
))
The correct result is generated by the script below, the other scrips generated a UUID however not the right one.
CONCAT(
substr(hex(Id), 7, 2), substr(hex(Id), 5, 2), substr(hex(Id), 3, 2), substr(hex(Id), 1, 2), '-'
, substr(hex(Id), 11, 2) , substr(hex(Id), 9, 2) , '-'
, substr(hex(Id), 15, 2) , substr(hex(Id), 13, 2) , '-'
, substr(hex(Id), 17, 4) , '-'
, substr(hex(Id), 21, 12)
)
Results running the other scripts generated wrong UUID as per below:
Expected UUID - 2e9660c2-1e51-4b9e-9a86-6db1a2770422
What was generated - c260962e-511e-9e4b-9a86-6db1a2770422
As you can see they are different.
Here's an alternative using concat_ws
Store raw uuid in a variable #x
SELECT #x := hex(uuid)
FROM foo;
Use CONCAT_WS and SUBSTR to parse human readable UUID
SELECT
LOWER(CONCAT_WS('-',
SUBSTR(#x, 1, 8),
SUBSTR(#x, 9, 4),
SUBSTR(#x, 13, 4),
SUBSTR(#x, 17, 4),
SUBSTR(#x, 21)
)) AS uuid;
According to this Jira ticket https://jira.mariadb.org/browse/MDEV-15854 UUID_TO_BIN and BIN_TO_UUID did not make into the Mariadb Server release 10.5. If you are using this version and under of Mariadb Server you will have to use a custom implementation mentioned above.

Set auto_increment value to each unique group

I've got a MySQL innodb table (sqlfiddle demo) with
id, name_id, name, content
And content like
1, NULL, 'Brian', 'Bridge to terabithia'
2, NULL, 'Brian', 'Pulp fiction'
3, NULL, 'Brian', 'Trainspotting'
4, NULL, 'Luke', 'Watchmen'
5, NULL, 'Luke', 'Constantine'
6, NULL, 'Tony', 'Dark knight'
7, NULL, 'Tony', 'Shutter Island'
8, NULL, 'John', 'Machinist'
9, NULL, 'John', 'Matrix'
10, NULL, 'John', 'Sin city'
11, NULL, 'John', 'Mad Max'
The id is unique to each row. But I can't get, how to set auto_increment name_id to each unique name.
Here's (sqlfiddle) what I'm trying to achieve.
1, 1, 'Brian', 'Bridge to terabithia'
2, 1, 'Brian', 'Pulp fiction'
3, 1, 'Brian', 'Trainspotting'
4, 2, 'Luke', 'Watchmen'
5, 2, 'Luke', 'Constantine'
6, 3, 'Tony', 'Dark knight'
7, 3, 'Tony', 'Shutter Island'
8, 4, 'John', 'Machinist'
9, 4, 'John', 'Matrix'
10, 4, 'John', 'Sin city'
11, 4, 'John', 'Mad Max'
Is it possible to do with MySQL only?
Thank you for reading.
The short answer is you can't do this automatically with only auto_increment, and you probably shouldn't either.
If really have reason to do this you would be much better off normalizing your database, creating a "names" table (name_id PK, name) and removing the "name" column from this table. Honestly I'm not sure what you can really gain from doing this in your example, but I imagine it might be an abstraction of the problem.

Add up a points column based on an id from within the same mysql table

OK the database is layed out as (only columns being used are listed):
Table Name: race_stats
Columns: race_id, user_id, points, tournament_id
Table Name: user
Columns: user_id, driver
Table Name: race
Columns: race_id, race_name
Table Name: tournament
Columns: tournament_id, tournament_name
This is my current query:
$query = "
SELECT user.user_id, user.driver, race_stats.points, race_stats.user_id,
SUM(race_stats.points) AS total_points "."
FROM user, race_stats, tournament, race "."
WHERE race.race_id=race_stats.race_id
AND user.user_id=race_stats.user_id
AND tournament.tournament_id=race_stats.tournament_id
GROUP BY driver
ORDER BY total_points DESC
LIMIT 0, 15
";
Ok the query works but it is adding them all up for all the available races from the race_stats.race_id column as the total points. I have racked my brain beyond recognition to fix this but I just can't quite seem to find the solution I need. I'm sure it has to be an easy fix but I just can't get it. Any help is greatly appreciated.
///////////////////EDITED WITH RAW VALUES//////////////////////
INSERT INTO `race_stats` (`id_race`, `race_id`, `user_id`, `f`, `s`, `race_interval`, `race_laps`, `led`, `points`, `total_points`, `race_status`, `tournament_id`, `driver`, `tournament_name`) VALUES
(1, 1, 4, 1, 4, '135.878', 60, '2', 180, 0, 'Running', 1, 'new_driver_5', ''),
(2, 1, 2, 2, 2, '-0.08', 60, '22', 175, 0, 'Running', 1, 'new_driver_38', ''),
(3, 1, 5, 3, 5, '-11.82', 60, '2', 170, 0, 'Running', 1, 'new_driver_94', ''),
(4, 2, 2, 1, 15, '138.691', 29, '6', 180, 0, 'Running', 2, 'new_driver_38', ''),
(5, 2, 15, 2, 9, '-16.12', 29, '8*', 180, 0, 'Running', 2, 'new_driver_44', ''),
(6, 2, 8, 3, 11, '-2:03.48', 29, '0', 165, 0, 'Running', 2, 'new_driver_83', ''),
Let me know if this is what you meant by raw values if not I can get some more data for you.
Just posting the solution here for completeness:
SELECT user.driver, race_stats.race_id,
SUM(race_stats.points) AS total_points "."
FROM user, race_stats "."
WHERE user.user_id=race_stats.user_id
GROUP BY user.driver, race.race_id
Here's the query you want (formatted for readability):
SELECT
u.driver,
SUM(rs.points) AS total_points
FROM user u
LEFT JOIN race_stats rs on rs.user_id = u.user_id
GROUP BY 1;
The advantage of using an outer join (ie LEFT JOIN) is that drivers who have no stats still get a row, but with null as total_points.
p.s. I don't know what the usage of "." in your query is all about, so I removed it.