Order MYSQL Result by references within a result - php

I have a SQL query that returns an array like this:
nr|id |reference
#1|"1311"|"0"
#2|"1731"|"1260"
#3|"1332"|"1261"
#4|"1312"|"1311"
#5|"1316"|"1312"
#6|"1261"|"1316"
#7|"1260"|"1332"
now the problem is that the 2nd column and the 3rd column represent the order of the items, so the correct order of the above array would be
1 - 4 - 5 - 6 - 3 - 7 - 2
because the 3rd column tells what the id is after which the current item follows.
is there any way to put this into an SQL Query? A solution to sort the array afterwards with PHP would be acceptable, too.

Note that MySQL does not support recursion, so you have to invent it in some way or (better) rearrange your problem so that it doesn't require it. Anyway, just for fun, here's a solution of sorts... (NOTE: I've used NULL to represent orphans)
SELECT *, FIND_IN_SET(nr,(
SELECT CONCAT_WS(',',a.nr,b.nr,c.nr,d.nr,e.nr,f.nr,g.nr)
FROM my_table a
LEFT
JOIN my_table b
ON b.reference = a.id
LEFT
JOIN my_table c
ON c.reference = b.id
LEFT
JOIN my_table d
ON d.reference = c.id
LEFT
JOIN my_table e
ON e.reference = d.id
LEFT
JOIN my_table f
ON f.reference = e.id
LEFT
JOIN my_table g
ON g.reference = f.id
LEFT
JOIN my_table h
ON h.reference = g.id
WHERE a.reference IS NULL
)) a FROM my_table ORDER BY a;
http://www.sqlfiddle.com/#!2/347578/1

Related

Mysql query can not retrieve data as per condition

I have one issue. I need to retrieve data from database as per some condition but some cases it fails. I am explaining my query below.
select b.member_id as b_member_id,
b.rest_name,
b.city,
b.proviance,
b.postal,
b.address,
b.country,
b.person,
b.mobile,
b.url,
b.status,
b.premium,
b.image,
b.business_phone_no,
b.email,
b.multiple_image,
b.latitude,
b.longitude,
b.quadrant,
d.member_id as d_member_id,
d.day_id,
d.cat_id,
d.subcat_id,
d.comment,
d.city,
d.special_images,
c.cat_id,
c.special,
sub.subcat_id,
sub.subcat_name,
sub.status,
sl.day_id,
sl.member_id,
sl.date_from,
sl.date_to
from db_restaurant_basic as b left join db_restaurant_detail as d on b.member_id=d.member_id
left join db_category as c on d.cat_id=c.cat_id
left join db_subcategory as sub on d.subcat_id=sub.subcat_id
left join db_special_images as sl on d.day_id=sl.day_id
where b.city='2' and d.day_id='4' and c.special='1'
and (((sl.date_from IS NULL or sl.date_from='') and (sl.date_to IS NULL or sl.date_to='')) or( sl.date_from <='2016-10-27' and sl.date_to >= '2016-10-27' ))
and b.status=1
and sub.status=1 group by d.subcat_id ORDER BY b_member_id DESC
Here my problem is some value also is coming which does not match the condition. Here b.city='2' but some value is coming which city=0 only also. Here i need the value should come as per proper matching. Please help me.
You are selecting d.city - from the db_restaurant_basic table - but the condition you set is b.city='2' - on the db_restaurant_detail table.
So any results with a city of 0, will show the city from the d / db_restaurant_detail table.
If you need to filter on that as well, you need to add and d.city=2.
You should probably check if you can normalize your database structure more to avoid having the same data in different tables.
Using the answer window's formatting options...
WHERE b.city = 2
AND d.day_id = 4 -- NOTE THAT THIS IS AN INNER JOIN!
AND c.special = 1 -- AND SO IS THIS !!
Since you have city twice in the selection list (b.city and d.city) I have to assume the city='0' value you mention is really d.city='0'. To make sure that also d.city is '2' you can add an additional condition in the where clause or you specify the join like this
select ... from db_restaurant_basic as b left join db_restaurant_detail as d on d.member_id=d.member_id and b.city = d.city left join ...
or even like this, getting rid of the ambiguity
select ... from db_restaurant_basic as b left join db_restaurant_detail as d using(member_id, city) left join ...

Mysql left join returns more than one row

I have 3 tables and some fields' names are the same. Here is the first table named semp:
The second one's name semp_k:
And the third is semp_y:
You see, the main table is the first and the others are related it. The first table has got 3 row. So when I fetch it, it must return 3 row. But when I fetch the first table, it multiples returned rows with sum of second and third table. Here is my code:
SELECT s.*, k.*, y.* FROM semp AS s LEFT JOIN semp_k AS k ON s.no = k.semp_no LEFT JOIN semp_y AS y ON s.no = y.semp_no WHERE s.durum = 1 ORDER BY s.bas_t DESC
use MySQL group by
group by s.no
or try this :-
SELECT
s.*, k.*, y.*
FROM
semp AS s
LEFT JOIN semp_k AS k ON s. NO = k.semp_no
LEFT JOIN semp_y AS y ON s. NO = y.semp_no
WHERE
s.durum = 1
GROUP BY s.no
ORDER BY
s.bas_t DESC
You need to use group by.
Your query should be like this ;
SELECT
s.*, k.*, y.*
FROM
semp AS s
LEFT JOIN semp_k AS k ON s. NO = k.semp_no
LEFT JOIN semp_y AS y ON s. NO = y.semp_no
WHERE
s.durum = 1
GROUP BY s.no
ORDER BY
s.bas_t DESC

Limiting a left join to returning one result?

I currently have this left join as part of a query:
LEFT JOIN movies t3 ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The trouble is that if there are several movies with the same name and same popularity (don't ask, it just is that way :-) ) then duplicate results are returned.
All that to say, I would like to limit the result of the left join to one.
I tried this:
LEFT JOIN
(SELECT t3.movie_name FROM movies t3 WHERE t3.popularity = 0 LIMIT 1)
ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The second query dies with the error:
Every derived table must have its own alias
I know what I'm asking is slightly vague since I'm not providing the full query, but is what I'm asking generally possible?
The error is clear -- you just need to create an alias for the subquery following its closing ) and use it in your ON clause since every table, derived or real, must have its own identifier. Then, you'll need to include movie_id in the subquery's select list to be able to join on it. Since the subquery already includes WHERE popularity = 0, you don't need to include it in the join's ON clause.
LEFT JOIN (
SELECT
movie_id,
movie_name
FROM movies
WHERE popularity = 0
ORDER BY movie_name
LIMIT 1
) the_alias ON t1.movie_id = the_alias.movie_id
If you are using one of these columns in the outer SELECT, reference it via the_alias.movie_name for example.
Update after understanding the requirement better:
To get one per group to join against, you can use an aggregate MAX() or MIN() on the movie_id and group it in the subquery. No subquery LIMIT is then necessary -- you'll receive the first movie_id per name withMIN() or the last with MAX().
LEFT JOIN (
SELECT
movie_name,
MIN(movie_id) AS movie_id
FROM movies
WHERE popularity = 0
GROUP BY movie_name
) the_alias ON t1.movie_id = the_alias.movie_id
LEFT JOIN movies as m ON m.id = (
SELECT id FROM movies mm WHERE mm.movie_id = t1.movie_id
ORDER BY mm.id DESC
LIMIT 1
)
you could try to add GROUP BY t3.movie_id to the first query
Try this:
LEFT JOIN
(
SELECT t3.movie_name, t3.popularity
FROM movies t3 WHERE t3.popularity = 0 LIMIT 1
) XX
ON t1.movie_id = XX.movie_id AND XX.popularity = 0
On MySQL 5.7+ use ANY_VALUE & GROUP_BY:
SELECT t1.id,t1.movie_name, ANY_VALUE(t3.popularity) popularity
FROM t1
LEFT JOIN t3 ON (t3.movie_id=t1.movie_id AND t3.popularity=0)
GROUP BY t1.id
more info
LEFT JOIN only first row
https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
Easy solution to left join the 1 most/least recent row is using select over ON phrase
SELECT A.ID, A.Name, B.Content
FROM A
LEFT JOIN B
ON A.id = (SELECT MAX(id) FROM B WHERE id = A.id)
Where A.id is the auto-incremental primary key.
LEFT JOIN (
SELECT id,movie_name FROM movies GROUP BY id
) as m ON (
m.id = x.id
)
// Mysql
SELECT SUM(db.item_sales_nsv) as total FROM app_product_hqsales_otc as db
LEFT JOIN app_item_target_otc as it ON
db.id = (SELECT MAX(id) FROM app_item_target_otc as ot WHERE id = db.id)
and db.head_quarter = it.hqcode
AND db.aaina_item_code = it.aaina_item_code AND db.month = it.month
AND db.year = it.year
WHERE db.head_quarter = 'WIN001' AND db.month = '5' AND db.year = '2022' AND db.status = '1'

Inner join query using multiple values

My table structure is as shown:
table:App
|AppID|AppName|AppType|
1 test new
table:AppRelease
|AppReleaseID|AppID|ReleaseDate|ReleaseVersion|
1 1 2012-06-20 2.2
2 1 2012-06-19 2.3
I write a query as shown below:
SELECT A.*,B.ReleaseDate,B.ReleaseVersion
FROM App as A
LEFT JOIN AppRelease as B ON A.AppID=B.AppID
This query is working for single value in AppRelease table, but multiple values in AppRelease table I want to get last added value. Is it possible in single query?
SELECT aa.*, bb.AppReleaseID, bb.ReleaseDate
FROM App aa LEFT JOIN (
SELECT a.AppID, a.AppReleaseID, a.ReleaseDate
FROM AppRelease a INNER JOIN (
SELECT AppID, MAX(ReleaseDate) mx FROM AppRelease
GROUP BY AppID
) b ON a.AppID = b.AppID AND a.ReleaseDate = b.mx
) bb ON bb.AppID = aa.AppID
fiddle: http://sqlfiddle.com/#!2/befa2/3
Using a JOIN I think the best you can do is select the maximum values from AppRelease.
SELECT A.*,MAX(B.ReleaseDate),MAX(B.ReleaseVersion)
FROM App as A
LEFT JOIN AppRelease as B ON A.AppID=B.AppID
GROUP BY A.AppID
If you want to semantically get the last-added value, you would probably be better off using subqueries, such as
SELECT A.*,
(SELECT B.ReleaseDate FROM AppRelease as B
WHERE B.AppID=A.AppID ORDER BY B.AppReleaseID DESC LIMIT 1)
as ReleaseDate,
(SELECT B.ReleaseVersion FROM AppRelease as
B WHERE B.AppID=A.AppID ORDER BY B.AppReleaseID DESC LIMIT 1)
as ReleaseVersion
FROM App as A
To achieve this in a single query you need to obtain the maximum value first in a subquery:
SELECT A.*,B.ReleaseDate,B.ReleaseVersion
FROM App as A
LEFT JOIN AppRelease as B ON A.AppID = B.AppI
WHERE B.ReleaseDate = (
SELECT MAX(ReleaseDate)
FROM AppRelease
WHERE AppID = A.AppID GROUP BY AppID
LIMIT 0, 1
) OR B.ReleaseDate IS NULL;
I think there's another way to do this by using the subquery as a join table.

Getting the maximum value from interrelated MySQL tables

I am trying to unify a pair of queries with a LEFT JOIN, so that I can perform an ORDER BY on a desired column.
Table A has an exclusive one-to-many relationship with Table B, and table B has an exclusive one-to-many relationship with Table C.
I want to get the maximum value of a column in Table C, for each row in Table A.
what I used to have was:
$tableA = SELECT * FROM tableA;
for each row in $tableA {
$maxValue = SELECT MAX(value) FROM tableC WHERE tableB_id IN (SELECT tableB_id FROM tableB WHERE tableA_id={$row['tableA_id']}) GROUP BY tableB_id;
}
and now I'm thinking along the lines of:
SELECT * FROM tableA LEFT JOIN (SELECT tableA_id, MAX(max_c_value) FROM (SELECT tableB_id, MAX(value) max_c_value FROM tableC GROUP BY tableB_id) t GROUP BY tableA_id) USING(tableA_id)
but I know that's gibberish. I am not sure where to go from here.
I'm finding it hard to explain the problem, sorry.
SELECT A.ID, MAX(C.MyField) as CField
FROM A
LEFT OUTER JOIN B
ON A.ID = B.A_ID
LEFT OUTER JOIN C
ON B.ID = C.B_ID
GROUP BY A.ID
You will get null value for CField if there is no rows corresponding.
select max(table3.field),table1.field from table1
join table2 on table1.id=table2.table1_id
join table3 on table2.id = table3.table2_id
group by table1.field
You were closer on the first try I think. You want something like this:
SELECT MAX(tableC.cValue) FROM tableA
LEFT JOIN tableB
ON tableA.tableA_id = tableB.tableA_id
LEFT JOIN tableC
ON tableB.tableB_id = tableC.tableB_id
http://www.w3schools.com/sql/sql_join.asp
I have managed to solve it on my own, only to come back here and find I was making things far too complicated for myself, getting lost in a sea of tables!
This code did actually work, but I have already replaced it with the simpler code suggested above:
SELECT * FROM A LEFT JOIN (
SELECT A_ID, MAX(val) FROM (
SELECT * FROM B LEFT JOIN (
SELECT B_ID, MAX(val) val FROM C GROUP BY B_ID
) x USING(B_ID)
) y GROUP BY A_ID
) z USING(A_ID);

Categories