select sorted tree and subtrees with materialized path - mysql

i want select tree from
id | parent_id | path | order
---------------------------------------
1 | 0 | /1/ | 1
2 | 1 | /1/2/ | 1
3 | 2 | /1/2/3/ | 1
4 | 1 | /1/4/ | 2
5 | 4 | /1/4/5/ | 2
6 | 4 | /1/4/6/ | 1
like this
| 1 | | |
| | 2 | |
| | | 3 |
| | 4 | |
| | | 6 |
| | | 5 |
in one query.
Something like
select * from tbl ORDER BY COALESCE(length(path),0), order asc
but this select sorted groups of each tree level
1
-2
-4
--3
--6
--5
thanks

Related

How to select row according to row in range of table 1 date with mysql?

I want to select picture file from photo_db where sid is the same as allotment_db so I wrote:
//allotment_db
+---------+---------+-----------+---------+
| id | rm_id | date | stts |
+---------+---------+-----------+---------+
| 1 | 1 |2019-10-01 | 1 |
| 2 | 2 |2019-10-01 | 1 |
| 3 | 3 |2019-10-01 | 1 |
| 4 | 1 |2019-10-02 | 1 |
| 5 | 2 |2019-10-02 | 1 |
+---------+---------+-----------+---------+
I want to select one row from photo_db ...
//photo_db
+---------+-----------+----------+-----------+
| id | rm_id | file | var |
+---------+-----------+----------+-----------+
| 1 | 1 | rm1.jpg | 0 |
| 2 | 1 | rm2.jpg | 0 |
| 3 | 1 | rm3.jpg | 9 |
| 4 | 2 | rm4.jpg | 0 |
| 5 | 2 | rm5.jpg | 9 |
| 6 | 2 | rm6.jpg | 0 |
| 7 | 3 | rm7.jpg | 0 |
| 8 | 3 | rm8.jpg | 0 |
| 9 | 3 | rm9.jpg | 9 |
| 10 | 1 | rm10.jpg | 0 |
+---------+-----------+----------+-----------+
Then, I wrote:
select *
from allotment_db alm
left
join photo_db pic
on pic.id = alm.id
where alm.date between '2019-10-01' and '2019-10-02'
and alm.stts = 1
and pic.var = 9
group
by alm.rm_id
And expect the result would come like this
//allotment_db
+---------+---------+-----------+---------+---------+
| id | rm_id | date | stts | file |
+---------+---------+-----------+---------+---------+
| 1 | 1 |2019-10-01 | 1 | rm3.jpg |
+---------+---------+-----------+---------+---------+
| 2 | 2 |2019-10-01 | 1 | rm5.jpg |
+---------+---------+-----------+---------+---------+
| 3 | 3 |2019-10-01 | 1 | rm9.jpg |
+---------+---------+-----------+---------+---------+
| 4 | 1 |2019-10-02 | 1 | rm3.jpg |
+---------+---------+-----------+---------+---------+
| 5 | 2 |2019-10-02 | 1 | rm5.jpg |
+---------+---------+-----------+---------+---------+
But the actual result return nothing even an error. Please correct me.
That is not how you should be using GROUP BY standard wise, also GROUP BY is not meant to "unduplicate" like that..
I assume you get a error when running your query?
SELECT list is not in GROUP BY clause and contains nonaggregated
column 'alm.id' which is not functionally dependent on columns in
GROUP BY clause; this is incompatible with
sql_mode=only_full_group_by"
From what it looks like you seams to be wanting these query resultsets to be merged as one resultset.
Query #1
SELECT
allotment_db.id
, allotment_db.rm_id
, allotment_db.date
, allotment_db.stts /* or (SELECT 1) AS stts -> 1 AS stts instead */
FROM
allotment_db
WHERE
allotment_db.date BETWEEN '2019-10-01' and '2019-10-02'
AND
stts = '1'
;
| id | rm_id | date | stts |
| --- | ----- | ---------- | ---- |
| 1 | 1 | 2019-10-01 | 1 |
| 2 | 2 | 2019-10-01 | 1 |
| 3 | 3 | 2019-10-01 | 1 |
| 4 | 1 | 2019-10-02 | 1 |
| 5 | 2 | 2019-10-02 | 1 |
Query #2
SELECT
photo_db.rm_id
, photo_db.file
FROM
photo_db
WHERE
photo_db.var = '9'
;
| rm_id | file |
| ----- | ------- |
| 1 | rm3.jpg |
| 2 | rm5.jpg |
| 3 | rm9.jpg |
So a option would be ..
Query
SELECT
allotment_db.id
, allotment_db.rm_id
, allotment_db.date
, allotment_db.stts /* or (SELECT 1) AS stts -> 1 AS stts instead */
, photo_db.rm_id
, photo_db.file
FROM (
SELECT
allotment_db.id
, allotment_db.rm_id
, allotment_db.date
, allotment_db.stts /* or (SELECT 1) AS stts -> 1 AS stts instead */
FROM
allotment_db
WHERE
allotment_db.date BETWEEN '2019-10-01' and '2019-10-02'
AND
stts = '1'
) AS allotment_db
INNER JOIN (
SELECT
photo_db.rm_id
, photo_db.file
FROM
photo_db
WHERE
photo_db.var = '9'
) AS photo_db
ON
allotment_db.rm_id = photo_db.rm_id
ORDER BY
id ASC
, allotment_db.rm_id ASC
Result
| id | rm_id | date | stts | rm_id | file |
| --- | ----- | ---------- | ---- | ----- | ------- |
| 1 | 1 | 2019-10-01 | 1 | 1 | rm3.jpg |
| 2 | 2 | 2019-10-01 | 1 | 2 | rm5.jpg |
| 3 | 3 | 2019-10-01 | 1 | 3 | rm9.jpg |
| 4 | 1 | 2019-10-02 | 1 | 1 | rm3.jpg |
| 5 | 2 | 2019-10-02 | 1 | 2 | rm5.jpg |
see demo

sql count() get wrong result

I have a table like this structure:
| event id | item 1 id | item 2 id | set |
| 1 | 1 | 2 | 1 |
| 1 | 1 | 3 | 1 |
| 1 | 2 | 1 | 1 |
| 1 | 2 | 3 | 1 |
| 1 | 3 | 1 | 1 |
| 1 | 3 | 2 | 1 |
| 1 | 2 | 4 | 2 |
| 1 | 4 | 2 | 2 |
| 2 | 1 | 4 | 3 |
| 2 | 1 | 5 | 3 |
| 2 | 4 | 1 | 3 |
| 2 | 4 | 5 | 3 |
| 2 | 5 | 1 | 3 |
| 2 | 5 | 4 | 3 |
now I wish to count the occurrence of item1 as well as item1 combined with item2 separately
I tried following:
with count_item1 AS (
select event_id, item_1_id, count(distinct set) AS c1 from table
group by event_id, item_1_id
), count_item1_and_item2 AS (
select event_id, item_1_id, item_2_id, count(distinct set) AS c2 from table
group by event_id, item_1_id, item_2_id
)
select t1.event_id, t1.item_1_id, t1.item_2_id, t1.c2, t2.c1
from count_item1_and_item2 AS t1
inner join count_item1 AS t2
on t1.event_id=t2.event_id and t1.item_1_id=t2.item_1_id
for example as table above
so the result for this should be:
| event id | item 1 id | item 2 id | c1 | c2 |
| 1 | 1 | 2 | 1 | 1 |
| 1 | 1 | 3 | 1 | 1 |
| 1 | 2 | 1 | 2 | 1 |
| 1 | 2 | 3 | 2 | 1 |
| 1 | 3 | 1 | 1 | 1 |
| 1 | 3 | 2 | 1 | 1 |
| 1 | 2 | 4 | 2 | 1 |
| 1 | 4 | 2 | 1 | 1 |
| 2 | 1 | 4 | 1 | 1 |
| 2 | 1 | 5 | 1 | 1 |
| 2 | 4 | 1 | 1 | 1 |
| 2 | 4 | 5 | 1 | 1 |
| 2 | 5 | 1 | 1 | 1 |
| 2 | 5 | 4 | 1 | 1 |
the meaning of each row is: in event_id, item 1 appeared c1 in distinct set and (item1, item2) appeared c2 in distinct set.
also count of (item1, item2) is equal to (item2, item1)
then I find a strange thing:
the occurrence of item1 itself should not less than the occurrence of item1 combined with item2, but I find that sometimes item1 combined with item2 has more count than count of item1, is there anything I did wrong here? I think my idea is right but I didn't get the result. I have being stacked in here for a weekend.

How to select multiple values for one table "cell" MySQL

For all players, I need to find the player number and a list of the numbers of teams for which they have ever played.
Here is the table "MATCHES":
+---------+--------+----------+-----+------+
| MATCHNO | TEAMNO | PLAYERNO | WON | LOST |
+---------+--------+----------+-----+------+
| 1 | 1 | 6 | 3 | 1 |
| 2 | 1 | 6 | 2 | 3 |
| 3 | 1 | 6 | 3 | 0 |
| 4 | 1 | 44 | 3 | 2 |
| 5 | 1 | 83 | 0 | 3 |
| 6 | 1 | 2 | 1 | 3 |
| 7 | 1 | 57 | 3 | 0 |
| 8 | 1 | 8 | 0 | 3 |
| 9 | 2 | 27 | 3 | 2 |
| 10 | 2 | 104 | 3 | 2 |
| 11 | 2 | 112 | 2 | 3 |
| 12 | 2 | 112 | 1 | 3 |
| 13 | 2 | 8 | 0 | 3 |
+---------+--------+----------+-----+------+
The best I could come up with was:
SELECT DISTINCT playerno, teamno
FROM matches
ORDER BY playerno;
which results in:
+----------+--------+
| playerno | teamno |
+----------+--------+
| 2 | 1 |
| 6 | 1 |
| 8 | 1 |
| 8 | 2 |
| 27 | 2 |
| 44 | 1 |
| 57 | 1 |
| 83 | 1 |
| 104 | 2 |
| 112 | 2 |
+----------+--------+
Notice how player 8 has played on two teams. How can I get the table to show only one row for player 8 and a list of teamno's (1 & 2)?
You could use the group_concat aggregate function:
SELECT playerno, GROUP_CONCAT(DISTINCT teamno)
FROM matches
GROUP BY playerno
ORDER BY playerno;
You could use group_concat
SELECT playerno, group_concat( teamno)
FROM matches
GROUP BY playerno;

Creating a log having the date of purchase

I need to create a log having the purchase date of an item.
Items can be owned by only one buyer at time. So, for example, if item1 was purchased by buyer2 in 2009 and after by buyer1 in 2015, then between 2009 and 2015 was owned by buyer2.
Here is my table:
+--------+------------+-----------+----------+
| id_doc | date | id_item | id_buyer |
+--------+------------+-----------+----------+
| 11 | 2016-06-07 | 1 | 4 |
| 10 | 2016-06-06 | 1 | 4 |
| 1 | 2015-11-30 | 1 | 1 |
| 9 | 2009-01-01 | 1 | 2 |
| 4 | 2001-01-12 | 1 | 2 |
| 8 | 1996-06-06 | 1 | 2 |
| 3 | 1995-05-29 | 1 | 1 |
| 2 | 1998-05-23 | 2 | 2 |
| 7 | 2014-10-10 | 3 | 2 |
| 6 | 2003-12-12 | 3 | 3 |
| 5 | 1991-01-12 | 3 | 2 |
+--------+------------+-----------+----------+
Here is a kind of table/view I need:
+------------+------------+-----------+----------+--------+
| date_from | date_to | id_item | id_buyer | id_doc |
+------------+------------+-----------+----------+--------+
| 2016-06-07 | - | 1 | 4 | 11 |
| 2016-06-06 | 2016-06-07 | 1 | 4 | 10 |
| 2015-11-30 | 2016-06-06 | 1 | 1 | 1 |
| 2009-01-01 | 2015-11-30 | 1 | 2 | 9 |
| 2001-01-12 | 2009-01-01 | 1 | 2 | 4 |
| 1996-06-06 | 2001-01-12 | 1 | 2 | 8 |
| 1995-05-29 | 1996-06-06 | 1 | 1 | 3 |
| 1998-05-23 | - | 2 | 2 | 2 |
| 2014-10-10 | - | 3 | 2 | 7 |
| 2003-12-12 | 2014-10-10 | 3 | 3 | 6 |
| 1991-01-12 | 2003-12-12 | 3 | 2 | 5 |
+------------+------------+-----------+----------+--------+
I've tried a lot with GROUP BY, GROUP_CONCAT, trying to access next record date, etc ... but I can't found out how to solve the problem.
Thanks in advance.
I finally found out the solution only for past purchases.
SELECT
main.id_doc, main.id_item, main.date AS "date_from", bi.date AS "date_to", main.id_buyer
FROM
MyTable main, MyTable bi
WHERE
bi.id_doc =
(
SELECT sub.id_doc
FROM MyTable sub
WHERE sub.id_item = main.id_item AND sub.date > main.date ORDER BY sub.date ASC LIMIT 1
);

How to return row of sum()s

I now find my original table structure was not good, so want to change it.
But I am having a hard time designing queries to obtain totals in rows with the new structure.
current structure:
+----------+-------+-------+-------+-------+
| state | shop | item0 | item1 | item2 |
+----------+-------+-------+-------+-------+
| 5 | 0 | 1 | 2 | 3 |
| 5 | 1 | 1 | 2 | 3 |
| 5 | 2 | 1 | 2 | 3 |
| 4 | 3 | 1 | 2 | 3 |
+----------+-------+-------+-------+-------+
(quantities of items at shop)
I want to change to these 2 tables:
shops table
+---------+--------+
| shop_id | state |
+---------+--------+
| 0 | 5 |
| 1 | 5 |
| 2 | 5 |
| 3 | 4 |
+---------+--------+
items table
+------------+--------------+
| shop | item | quantity |
+------------+--------------+
| 0 | 0 | 1 |
| 0 | 1 | 2 |
| 0 | 2 | 3 |
| 1 | 0 | 1 |
| 1 | 1 | 2 |
| 1 | 2 | 3 |
| 2 | 0 | 1 |
| 2 | 1 | 2 |
| 2 | 2 | 3 |
| 3 | 0 | 1 |
| 3 | 1 | 2 |
| 3 | 2 | 3 |
+------------+--------------+
The old layout allowed simple queries for getting totals by row:
SELECT state,SUM(item0) t0,SUM(item1) t1,SUM(item2) t2
FROM shops
WHERE state=5
+--------+---------+---------+----------+
| state | t0 | t1 | t2 |
+--------+---------+---------+----------+
| 5 | 3 | 6 | 9 |
+--------+---------+---------+----------+
With the new structure,
I can get the totals in column as follows:
SELECT item,SUM(quantity) total
FROM shops
LEFT JOIN items ON shop=shopid
WHERE state=5
GROUP by item
+--------+---------+
| item | total |
+--------+---------+
| 0 | 3 |
+--------+---------+
| 1 | 6 |
+--------+---------+
| 2 | 9 |
+--------+---------+
but how do I get the totals in rows:
+--------+---------+---------+----------+
| state | t0 | t1 | t2 |
+--------+---------+---------+----------+
| 4 | 1 | 2 | 3 |
| 5 | 3 | 6 | 9 |
+--------+---------+---------+----------+
You might try using a few more JOINs:
SELECT S.state,
SUM(T0.quantity) AS "T0",
SUM(T1.quantity) AS "T1",
SUM(T2.quantity) AS "T2"
FROM shops AS S
LEFT JOIN items AS T0 ON S.shop_id = T0.shop_id AND T0.item=0
LEFT JOIN items AS T1 ON S.shop_id = T1.shop_id AND T1.item=1
LEFT JOIN items AS T2 ON S.shop_id = T2.shop_id AND T2.item=2
GROUP BY S.state
There might be an easier way.