How to store multiple relationships in MySql - mysql

If I have multiple objects and anyone can potentially map to multiple other ones.
A -> B, C, D, E
B -> A, E, F, C
C -> B
etc.
How would I store these entities in MySql and use JPA + Hibernate to manage them. For example, If I search "A", it will return "B,C,D,E", and if I search "C", it will return "B", etc.
Edited:
Follow suggestion, I did the following:
[test]> describe relation;
+----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| id_start | int(11) | YES | | NULL | |
| id_end | int(11) | YES | MUL | NULL | |
+----------+---------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
MariaDB [test]> describe entity;
+-------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(5) | YES | | NULL | |
+-------+------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
MariaDB [test]> select * from entity;
+----+------+
| id | name |
+----+------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
| 5 | E |
| 6 | F |
+----+------+
6 rows in set (0.00 sec)
MariaDB [test]> select * from relation;
+----+----------+--------+
| id | id_start | id_end |
+----+----------+--------+
| 1 | 3 | 1 |
| 2 | 2 | 1 |
| 3 | 4 | 1 |
| 4 | 5 | 1 |
| 5 | 1 | 2 |
| 6 | 5 | 2 |
| 7 | 6 | 2 |
| 8 | 3 | 2 |
| 9 | 2 | 3 |
+----+----------+--------+
9 rows in set (0.00 sec)
[test]> select E.name, R.id_start from relation R join entity E on E.id=R.id_end where E.name="A";
+------+----------+
| name | id_start |
+------+----------+
| A | 3 |
| A | 2 |
| A | 4 |
| A | 5 |
+------+----------+
Question:
This query returns the related Ids of 'A', which is right, but not actually B, C, D, E. How to get the actual related names from entity table? Is it a database design or SQL statement mistake?

Related

MYSQL: How to select every 4th row STARTING from 3rd row?

meaning the result should be selecting 3rd, 7th, 11th, 15 rows etc.
Every row has an ID, in ascending order.
I am stuck on this for hours! Any help is highly appreciated!
A simpler way would be to use mod on the id itself:
select * from table where (id + 1) mod 4 = 0;
Suppose your schema is:
CREATE TABLE t1 (
id int(11) DEFAULT NULL,
data varchar(20) DEFAULT NULL
);
mysql> select * from t1;
+------+--------+
| id | data |
+------+--------+
| 1 | abc-1 |
| 2 | abc-2 |
| 3 | abc-3 |
| 4 | abc-4 |
| 5 | abc-5 |
| 6 | abc-6 |
| 7 | abc-7 |
| 8 | abc-8 |
| 9 | abc-9 |
| 10 | abc-10 |
| 11 | abc-11 |
| 12 | abc-12 |
| 13 | abc-13 |
| 14 | abc-14 |
| 15 | abc-15 |
| 16 | abc-16 |
+------+--------+
16 rows in set (0.00 sec)
mysql> select id,data from (select mod(#r:=#r+1,4) as isfetch,id,data from t1,(select #r:=0) s) k where k.isfetch=0 order by id;
+------+--------+
| id | data |
+------+--------+
| 4 | abc-4 |
| 8 | abc-8 |
| 12 | abc-12 |
| 16 | abc-16 |
+------+--------+
4 rows in set (0.01 sec)

How to find some specific records without using sub query in mysql

I have 2 tables in my database. Both of have approx 100M records.My first table uph contains order's details and another urs contains customer's details. Their structure is:
mysql> desc uph;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| uid | int(11) | NO | | NULL | |
| order_from | varchar(255) | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
mysql> desc usr;
+---------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+----------------+
| uid | int(11) | NO | PRI | NULL | auto_increment |
| profile | char(10) | NO | | NULL | |
+---------+----------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
Both table have data like this:
mysql> select * from usr;
+-----+----------+
| uid | profile |
+-----+----------+
| 1 | in-store |
| 2 | ecom |
| 3 | ecom |
| 4 | in-store |
| 5 | ecom |
+-----+----------+
4 rows in set (0.00 sec)
mysql> select * from uph;
+----+-----+------------+
| id | uid | order_from |
+----+-----+------------+
| 1 | 1 | in-store |
| 2 | 2 | ecom |
| 3 | 1 | ecom |
| 4 | 4 | in-store |
+----+-----+------------+
4 rows in set (0.00 sec)
Now, I want to find those users which have profile "ecom" and if they've done any purchase then order_from should only be "ecom". If not purchsed anything only having profile, still will be considered as an "ecom" user.
If any user purchased from ecom and In-store both, those will be excuded from results. Which means users should not have any relation with In-store.
So in the output of the query we'll have the result like:
+----+
| uid |
+-----+
| 2 |
| 3 |
| 5 |
+-----+
As both tables contains heavy data so I'm restricted to user sub-query. Please suggest how to do it without using sub-query.
You can do a join and check the aggregated results for your criteria
select u.uid, u.profile
from usr u
left join uph p on u.uid = p.uid
where u.profile = 'ecom'
group by u.uid, u.profile
having sum(case when p.order_from = 'in-store' then 1 else 0 end) = 0

how can i get the name which age is max in his grade

how can i get the name who's age is max in his grade
Table information:
mysql> select * from stu;
+----+------+------+-------+
| id | name | age | grade |
+----+------+------+-------+
| 1 | a | 11 | 1 |
| 2 | b | 12 | 1 |
| 3 | c | 13 | 1 |
| 4 | d | 11 | 2 |
| 5 | e | 12 | 2 |
| 6 | f | 13 | 2 |
+----+------+------+-------+
6 rows in set (0.00 sec)
mysql> describe stu;
+-------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | char(1) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| grade | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
in this way i can get the max age and grade,but how can i get the name who's age is max in his grade.
mysql> select max(age),grade from stu group by grade;
+----------+-------+
| max(age) | grade |
+----------+-------+
| 13 | 1 |
| 13 | 2 |
+----------+-------+
2 rows in set (0.00 sec)
You could try this:
SELECT A.*
FROM STU A
INNER JOIN (SELECT MAX(AGE) AS MAX_AGE,GRADE FROM STU GROUP BY GRADE ) B ON A.GRADE = B.GRADE AND A.AGE= B.MAX_AGE
Try this:
select max(name), max(age),grade from stu
group by grade

order by inside group_contact mysql

I have a below mysql query. It's returns wrong value. Please HELP ME to resolve this issue.
SELECT
T1.PARENT_ID,
GROUP_CONCAT(
IF(T2.PROPERTIES IS NULL, "NA", T2.PROPERTIES)
ORDER BY T1.ORDER_INDEX ASC
) AS DATA
FROM TABLE_1 T1
JOIN TABLE_2 T2
ON T1.ID=T2.ID
WHERE T1.AUTHOR="123"
GROUP BY T1.PARENT_ID
ORDER BY T1.PARENT_ID;
Mysql Version ===> 5.0.27-standard-log
The above query returns:
+-----------+---------------+
| parent_id | data |
+-----------+---------------+
| 12345 | te,test1,test |
| 23456 | NA |
+-----------+---------------+
2 rows in set (0.00 sec)
_
But, it should be:
+-----------+---------------+
| parent_id | data |
+-----------+---------------+
| 12345 | NA,test1,test |
| 23456 | NA |
+-----------+---------------+
2 rows in set (0.00 sec)
-
-
########################### TABLE DATA ############################
mysql> select * from Table_1;
+----+-----------+--------+-------------+
| id | parent_id | author | order_index |
+----+-----------+--------+-------------+
| 1 | 12345 | 123 | 3 |
| 2 | 12345 | 123 | 1 |
| 3 | 23456 | 123 | 1 |
| 4 | 12345 | 123 | 2 |
+----+-----------+--------+-------------+
4 rows in set (0.00 sec)
mysql> select * from Table_2;
+----+------------+
| id | properties |
+----+------------+
| 1 | test |
| 2 | NULL |
| 3 | NULL |
| 4 | test1 |
+----+------------+
4 rows in set (0.00 sec)
-
-
########################### TABLE MODEL ############################
mysql> desc Table_1;
+-------------+-----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------+------+-----+---------+-------+
| id | int(11) | NO | PRI | | |
| parent_id | char(100) | YES | | NULL | |
| author | char(100) | YES | | NULL | |
| order_index | int(11) | YES | | 0 | |
+-------------+-----------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> desc Table_2;
+------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+-------+
| id | int(11) | NO | PRI | | |
| properties | text | YES | | NULL | |
+------------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)

Disturbing mysql behaviour around DECIMAL datatype conversion

So, here is the structure:
mysql> describe tier;
+---------------------+----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+----------------+------+-----+---------+----------------+
| ID | int(10) | NO | PRI | NULL | auto_increment |
| UP_TO | decimal(21,10) | YES | | NULL | |
+---------------------+----------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
Then the datas:
mysql> select id, up_to from tier;
+----+-----------------+
| id | up_to |
+----+-----------------+
| 1 | 1000.0000000000 |
| 2 | 2000.0000000000 |
| 3 | 3000.0000000000 |
| 4 | 500.0000000000 |
| 5 | 1000.0000000000 |
| 6 | 1500.0000000000 |
| 7 | 100.0000000000 |
| 8 | 200.0000000000 |
| 9 | 1000.0000000000 |
| 10 | 2000.0000000000 |
| 11 | 100.0000000000 |
| 12 | 200.0000000000 |
+----+-----------------+
12 rows in set (0.00 sec)
Then there's a little transformation:
mysql> SELECT id, TRIM(TRAILING '.' FROM TRIM(TRAILING '0' FROM CAST(up_to AS CH
AR) )) as converted from tier;
+----+-----------+
| id | converted |
+----+-----------+
| 1 | 1000 |
| 2 | 2000 |
| 3 | 3000 |
| 4 | 500 |
| 5 | 1000 |
| 6 | 1500 |
| 7 | 100 |
| 8 | 200 |
| 9 | 1000 |
| 10 | 2000 |
| 11 | 100 |
| 12 | 200 |
+----+-----------+
12 rows in set (0.00 sec)
Fine.
Let's put that in a stored function to be handy!
DELIMITER //
CREATE FUNCTION strip_trailing_zero(I_DEC DECIMAL(10,7)) RETURNS VARCHAR(20) DETERMINISTIC
BEGIN
DECLARE strBuff VARCHAR(20);
DECLARE cnt NUMERIC(2);
DECLARE tString VARCHAR(20);
SELECT CAST(I_DEC AS CHAR) INTO tString;
SELECT LOCATE('.',tString) INTO cnt;
IF cnt > 0 THEN
SELECT TRIM(TRAILING '.' FROM TRIM(TRAILING '0' FROM tString)) INTO strBuff;
ELSE
SET strBuff = tString;
END IF;
RETURN strBuff;
END//
DELIMITER ;
Cool.
GRANT EXECUTE ON FUNCTION mysql.strip_trailing_zero TO 'whatever'#'localhost';
At last, trying out my new toy now... :
mysql> select id, mysql.strip_trailing_zero(`up_to`) as converted_2 from tier;
+----+-------------+
| id | converted_2 |
+----+-------------+
| 1 | 999.9999999 |
| 2 | 999.9999999 |
| 3 | 999.9999999 |
| 4 | 500 |
| 5 | 999.9999999 |
| 6 | 999.9999999 |
| 7 | 100 |
| 8 | 200 |
| 9 | 999.9999999 |
| 10 | 999.9999999 |
| 11 | 100 |
| 12 | 200 |
+----+-------------+
12 rows in set, 7 warnings (0.02 sec)
Well, then, f*ck you too mysql!
No seriously, that's a silly joke. I'm convinced I did something wrong and there's a floating point conversion in the middle but I just can't figure it out!
Help welcome!
Thanks.
S.
edit: result after changing the input parameter type to DECIMAL(21,10):
mysql> select id, mysql.strip_trailing_zero(`up_to`) as converted_2 from tier;
+----+-------------+
| id | converted_2 |
+----+-------------+
| 1 | 1000 |
| 2 | 2000 |
| 3 | 3000 |
| 4 | 500 |
| 5 | 1000 |
| 6 | 1500 |
| 7 | 100 |
| 8 | 200 |
| 9 | 1000 |
| 10 | 2000 |
| 11 | 100 |
| 12 | 200 |
+----+-------------+
12 rows in set (0.02 sec)
Problem solved... Great! thank you!
Your UP_TO field in your table is defined as decimal(21,10), but your function takes in a decimal(10,7). I imagine that is stripping your value.
Try changing your function to accept decimal(21,10) instead.