Inner join query using multiple values - php

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.

Related

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

Order MYSQL Result by references within a result

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

SQL to select common as well as remaining data using JOIN in MySQL

I have three tables: wi_district, wi_group, and wi_training. I need to count groups and trainings based on districts. For this purpose I have used following SQL;
SQL1
SELECT wi_district.dst_name, COUNT(grp_id) AS group_count, MAX(grp_created_date) as grp_created_date
FROM wi_group
INNER JOIN wi_district ON wi_district.dst_id=wi_group.grp_dst_id AND wi_group.grp_deleted=0 AND wi_group.grp_type IN (3)
GROUP BY wi_district.dst_name
The query counts group for each district. Likewise,
SQL2
SELECT wi_district.dst_name, COUNT(trn_id) AS training_count, MAX(trn_created_date) as trn_created_date
FROM wi_training
INNER JOIN wi_district ON wi_district.dst_id=wi_training.dst_id AND wi_training.trn_deleted=0 AND wi_training.trn_beneficiary_type IN (-1,2,8,9,10)
GROUP BY wi_district.dst_name
The query counts training for each district. Now I need to combine all the results obtained from SQL1 and SQL2 and get the result in the form of
dst_name || group_count || grp_created_date || training_count || trn_created_date
The problem is whenever I used SQL1 LEFT JOIN SQL2 then it displayed the result respective to SQL1 where the result of SQL2 can't be obtained and vice-versa. Please help me sort out with this problem in MySQL
I think you can join the filtered tables and then group by the district name. Like so:
SELECT dist.dst_name AS dst_name,
COUNT(grp.grp_id) AS group_count, MAX(grp.grp_created_date) AS grp_created_date,
COUNT(trn.trn_id) AS training_count, MAX(trn.trn_created_date) AS trn_created_date
FROM wi_district AS dist
LEFT JOIN (
SELECT dst_id, trn_id, trn_created_date
FROM wi_training
WHERE trn_deleted=0
AND trn_beneficiary_type IN (-1,2,8,9,10)
) AS trn ON trn.dst_id=dist.dst_id
LEFT JOIN (
SELECT grp_dst_id, grp_id, grp_created_date
FROM wi_group
WHERE grp_deleted=0
AND grp_type IN (3)
) AS grp ON grp.grp_dst_id = dist.dst_id
GROUP BY dist.dst_name
Why use names like dst_name? It is better to write out the full name, so you will also understand what it means after a few months.
Anyway, this query should do the trick
select d.dst_name as district
, count(distinct g.grp_id) as group_count
, max(grp_created_date) as group_created_date
, count(distinct trn_id) as training_count
, max(trn_created_date) as trn_created_date
from wi_district d
left join wi_group g on d.dst_id = g.grp_dst_id
and g.grp_deleted = 0
and g.grp_type in (3)
left join wi_training t on d.dst_id = t.dst_id
and t.trn_deleted = 0
and t.trn_beneficiary_type IN (-1,2,8,9,10)
group by d.dst_name
You need to DRIVE it from the grouping table. Like so.
SELECT D.dst_name, COUNT(grp_id) AS group_count, MAX(grp_created_date) as grp_created_date, COUNT(trn_id) AS training_count, MAX(trn_created_date) as trn_created_date
FROM wi_district D
LEFT JOIN wi_group G ON D.dst_id = G.grp_dst_id AND G.grp_deleted=0 AND G.grp_type IN (3)
LEFT JOIN wi_training T ON D.dst_id = T.dst_id AND T.trn_deleted=0 AND T.trn_beneficiary_type IN (-1,2,8,9,10)
GROUP BY wi_district.dst_name
And if you only want rows if they exist on either table, add a clause:
WHERE NOT G.grp_dst_id IS NULL OR NOT D.dst_id IS NULL

Reducing mySQL queries and time

I am currently working on speeding up a website, that is returning 300,000+ rows from a query. While I don't think this is too much of a load on the DB server, this query is happening in a while loop depending on the number of 'galleries' a user has.
For example Joe has 10 galleries in his account. Each of those galleries has x number of images, which have x number of comments on those images. So the query that is currently being run...
SELECT count(*) as total
FROM galleryimage a
INNER JOIN imagecomments b ON a.id=b.imgId
WHERE a.galleryId='".$row['id']."'
AND b.note <> ''
...is looking through all the galleryimage table 334,000 rows and the imagecomments table 76,000 rows and returning the result on each gallery. The query run on a single gallery returns a result in about 578ms, but with many galleries, say 30-40 you could be looking at a page load time of 17+ secs. Any suggestions on how to deal with this issue?
I cannot change the DB architecture....
Query for gallery id
SELECT a.id,
a.created,
a.name,
b.clientName,
a.isFeatured,
a.views,
a.clientId
FROM gallery a
INNER JOIN client b
ON a.clientId = b.id
WHERE a.isTemp = 0
AND a.clientRef = '{$clientRef}'
AND a.finish='1'
AND a.isArchive='0'
ORDER BY created
DESC
You can consolidate the queries and eliminate the need for looping:
SELECT
a.id,
a.created,
a.name,
b.clientName,
a.isFeatured,
a.views,
a.clientId,
COALESCE(c.img_cnt, 0) AS gallery_image_count,
COALESCE(c.comment_cnt, 0) AS gallery_comment_count
FROM
gallery a
INNER JOIN
client b ON a.clientId = b.id
LEFT JOIN
(
SELECT aa.galleryId,
COUNT(DISTINCT aa.id) AS img_cnt,
COUNT(1) AS comment_cnt
FROM galleryimage aa
INNER JOIN imagecomments bb ON aa.id = bb.imgId
WHERE bb.note <> ''
GROUP BY aa.galleryId
) c ON a.id = c.galleryId
WHERE
a.isTemp = 0 AND
a.clientRef = '{$clientRef}' AND
a.finish = 1 AND
a.isArchive = 0
ORDER BY
a.created 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'

Categories