Include sorting in query - php

I recently added a sorting field and now I want to sort the result. I could do it in PHP or directly on the database. So I tried the second one:
SELECT *
FROM constructions
AS whole
INNER JOIN
(
SELECT DISTINCT construction
FROM data
AS results
WHERE product =2
AND application =1
AND requirement =1
)
ON whole.id = results
ORDER BY whole.sorting
I tried to use inner join to match the complete table with the result set. But I can't get it working (#1248 - Every derived table must have its own alias). I tried to use the alias but something is still wrong. Perhaps I shouldn't user inner join and use IN() instead.

2 obvious errors in the syntax:
SELECT *
FROM constructions
AS whole
INNER JOIN
(
SELECT DISTINCT construction AS results
FROM data
WHERE product =2
AND application =1
AND requirement =1
) AS a
ON whole.id = a.results
ORDER BY whole.sorting

Try to get data like this...
SELECT *
FROM constructions
where
construction
in
(
SELECT DISTINCT construction
FROM data
AS results
WHERE product =2
AND application =1
AND requirement =1
)

Related

Paginate items from different sources

Here's a problem I'm facing: I need to lists some items. Those items come from different sources (let's say table A, table B, table C), with different attributes and nature (although some are common).
How can I merge them together in a list that is paginated?
The options I've considered:
Get them all first, then sort and paginate them afterwards in the code. This doesn't work well because there are too many items (thousands) and performance is a mess.
Join them in a SQL view with their shared attributes, once the SQL query is done, reload only the paginated items to get the rest of their attributes. This works so far, but might become difficult to maintain if the sources change/increase.
Do you know any other option? Basically, what is the most used/recommended way to paginate items from two data sources (either in SQL or directly in the code).
Thanks.
If UNION solves the problem, here are some syntax and optimization tips.
This will provide page 21 of 10-row pages:
(
( SELECT ... LIMIT 210 )
UNION [ALL|DISTINCT]
( SELECT ... LIMIT 210 )
) ORDER BY ... LIMIT 10 OFFSET 200
Note that 210 = 200+10. You can't trust using OFFSET in the inner SELECTs.
Use UNION ALL for speed, but if there could be repeated rows between the SELECTs, then explicitly say UNION DISTINCT.
If you take away too many parentheses, you will get either syntax errors or the 'wrong' results.
If you end up with a subquery, repeat the ORDER BY but not the LIMIT:
SELECT ...
FROM (
( SELECT ... LIMIT 210 )
UNION [ALL|DISTINCT]
( SELECT ... LIMIT 210 )
ORDER BY ... LIMIT 10 OFFSET 200
) AS u
JOIN something_else ON ...
ORDER BY ...
One reason that might include a JOIN is for performance -- The subquery u has boiled the resultset down to only 10 rows, hence the JOIN will have only 10 things to look up. Putting the JOIN inside would lead to lots of joining before whittling down to only 10.
I actually had to answer a similar situation very recently, specifically reporting across two large tables and paginating across both of them. The answer I came to was to use subqueries, like so:
SELECT
t1.id as 't1_id',
t1.name as 't1_name',
t1.attribute as 't1_attribute',
t2.id as 't2_id',
t2.name as 't2_name',
t2.attribute as 't2_attribute',
l.attribute as 'l_attribute'
FROM (
SELECT
id, name, attribute
FROM
table1
/* You can perform joins in here if you want, just make sure you're using your aliases right */
/* You can also put where statements here */
ORDER BY
name DESC, id ASC
LIMIT 0,50
) as t1
INNER JOIN (
SELECT
id,
name,
attribute
FROM
table2
ORDER BY
attribute ASC
LIMIT 250,50
) as t2
ON t2.id IS NOT NULL
LEFT JOIN
linkingTable as l
ON l.t1Id = t1.id
AND l.t2Id = t2.id
/* Do your wheres and stuff here */
/* You shouldn't need to do any additional ordering or limiting */

2 INNER JOIN For 2 colums that use the same foreign key

First, I have my database like this:
And the relations:
And now in the .php I want to create the table that shows everything in the table but instead of showing ProductId and UpgradeProductId as a number, I want to show them as name of the product
The problem is how can I do it? I already made this
And it show up like this
I want the [UpgradeProductId] to come out as Product Name like [ProductId] but I don't know how to write it to connect the SQL and have a result.
I hope I understood your question correctly.
The easy way to display the ProductName for your UpgradeProductId would be a SELECT statement for the column.
The statement would look like that:
SELECT UpgradeId, Productname, (SELECT Product.ProductName FROM Product WHERE Product.ProductId = Upgrade.UpgradeProductId), UpgradeDate, UpgradeDetail
FROM Upgrade
INNER JOIN Product ON Upgrade.ProductId = Product.ProductId
INNER JOIN RepairMan ON Upgrade.RepairManId = RepairMan.RepairManId
WHERE Upgrade.RepairManId = '$RepairManId'
ORDER BY UpgradeId ASC
However I guess, that this is not the most efficient solution.
To do the same with joins, you have to use aliases for your joined tables. It would look like this:
SELECT UpgradeId, P1.Productname, P2.Productname, UpgradeDate, UpgradeDetail
FROM Upgrade
INNER JOIN Product AS P1 ON Upgrade.ProductId = P1.ProductId
INNER JOIN Product AS P2 ON Upgrade.UpgradeProductId = P2.ProductId
INNER JOIN RepairMan ON Upgrade.RepairManId = RepairMan.RepairManId
WHERE Upgrade.RepairManId = '$RepairManId'
ORDER BY UpgradeId ASC
Another thing besides that. I don't know exactly which SQL you are using, but be sure to add either ASC or DESC to your ORDER command. Without this addition, some types of SQL tend to not order as you intended.

how to identify a column in mysql when I have 2 with same name [duplicate]

This question already has answers here:
How to resolve ambiguous column names when retrieving results?
(11 answers)
Closed 2 years ago.
I'm using this PHP code to get my sql query which joins 2 tables ... both table have the same "size" field, but the results is not the same in both... code:
mysql_query("SELECT * FROM cart INNER JOIN tbl_product ON tbl_product.product_id =
cart.product_id WHERE .......) or die(mysql_error());
The result of this query shows me
Cart_id, member_id, product_id, size, .... and a second size
1 of the size comes the cart table and 1 from the product table..
then I try to retrieve my data
while($data2 = mysql_fetch_array( $data))
{
$size= $data2['size'];
But I get the second size in my result and I need the first one.. I need the cart.size ... how can I do this ?
Name the columns explicitly in your SELECT statement, and assign ALIASes to the columns with identical names:
SELECT cart.id_col, cart.size AS CartSize, ttbl_product.size AS ProductSize
FROM cart INNER JOIN tbl_product ON tbl_product.product_id = cart.product_id
WHERE .......
then extract the value for ProductSize from the results.
If you don't need the cart size, you can eliminate it from the list of columns return and leave out the ALIAS, as you'll only have a single Size column in the results:
SELECT cart.id_col, ttbl_product.size
FROM cart INNER JOIN tbl_product ON tbl_product.product_id = cart.product_id
WHERE .......
In general, it's a good idea to explicitly name the columns you want in your SELECT statement as it makes it clearer what you're getting back, it will fail sooner if you are trying to get a column that's not there (when the SELECT executes, not when you try to retrieve the column value from the result set), and can lead to better performance if you're only interested in a small-ish subset of the available columns.
A select_expr can be given an alias using AS alias_name. The alias is
used as the expression's column name [...]
This is a basic feature of the SELECT statement in SQL. Please consult the manual: http://dev.mysql.com/doc/refman/5.0/en/select.html
Use SQL aliases. For examle:
SELECT a.a AS aa, b.a AS ba FROM tbl1 AS a, tbl2 AS b
Change SELECT * to SELECT [fields] where you manually specify which fields you need. If you only need one then there's nothing left to do. If you need both then you can use an alias for the fields like this:
SELECT p.size AS product_size, c.size AS cart_size FROM ...
Then they will be available in your array as keys product_size and cart_size.
Try this:
mysql_query("SELECT cart.size as cartsize, tbl_product.size as productsize, ...
FROM cart INNER JOIN tbl_product ON tbl_product.product_id = cart.product_id
WHERE ...) or die(mysql_error());
But if you don't work on some legacy code you don't want to rewrite completely use PDO instead, like suggested in first the comment.
Several comments to begin with:
I suggest to move away from mysql_* as soon as you can
Try not to use the * operator in your select statements
As for your question, use an alias for the two columns, I also like to give my tables a simpler alias (makes the query more concise):
SELECT t1.id, t1.size AS cart_size, t2.size AS product_size FROM cart t1
INNER JOIN tbl_product t2 ON t1.product_id = t2.product_id
Hope this helps.

MySql - Joining another table with multiple rows, inserting a query into a another query?

I've been racking my brain for hours trying work out how to join these two queries..
My goal is to return multiple venue rows (from venues) based on certain criteria... which is what my current query does....
SELECT venues.id AS ven_id,
venues.venue_name,
venues.sub_category_id,
venues.score,
venues.lat,
venues.lng,
venues.short_description,
sub_categories.id,
sub_categories.sub_cat_name,
sub_categories.category_id,
categories.id,
categories.category_name,
((ACOS( SIN(51.44*PI()/180)*SIN(lat*PI()/180) + COS(51.44*PI()/180)*COS(lat*PI()/180)*COS((-2.60796 - lng)*PI()/180)) * 180/PI())*60 * 1.1515) AS dist
FROM venues,
sub_categories,
categories
WHERE
venues.sub_category_id = sub_categories.id
AND sub_categories.category_id = categories.id
HAVING
dist < 5
ORDER BY score DESC
LIMIT 0, 100
However, I need to include another field in this query (thumbnail), which comes from another table (venue_images). The idea is to extract one image row based on which venue it's related to and it's order. Only one image needs to be extracted however. So LIMIT 1.
I basically need to insert this query:
SELECT
venue_images.thumb_image_filename,
venue_images.image_venue_id,
venue_images.image_order
FROM venue_images
WHERE venue_images.image_venue_id = ven_id //id from above query
ORDER BY venue_images.image_order
LIMIT 1
Into my first query, and label this new field as "thumbnail".
Any help would really be appreciated. Thanks!
First of all, you could write the first query using INNER JOIN:
SELECT
...
FROM
venues INNER JOIN sub_categories ON venues.sub_category_id = sub_categories.id
INNER JOIN categories ON sub_categories.category_id = categories.id
HAVING
...
the result should be identical, but i like this one more.
What I'd like to do next is to JOIN a subquery, something like this:
...
INNER JOIN (SELECT ... FROM venue_images
WHERE venue_images.image_venue_id = ven_id //id from above query
ORDER BY venue_images.image_order
LIMIT 1) first_image
but unfortunately this subquery can't see ven_id because it is evaluated first, before the outer query (I think it's a limitation of MySql), so we can't use that and we have to find another solution. And since you are using LIMIT 1, it's not easy to rewrite the condition you need using just JOINS.
It would be easier if MySql provided a FIRST() aggregate function, but since it doesn't, we have to simulate it, see for example this question: How to fetch the first and last record of a grouped record in a MySQL query with aggregate functions?
So using this trick, you can write a query that extracts first image_id for every image_venue_id:
SELECT
image_venue_id,
SUBSTRING_INDEX(
GROUP_CONCAT(image_id order by venue_images.image_order),',',1) as first_image_id
FROM venue_images
GROUP BY image_venue_id
and this query could be integrated in your query above:
SELECT
...
FROM
venues INNER JOIN sub_categories ON venues.sub_category_id = sub_categories.id
INNER JOIN categories ON sub_categories.category_id = categories.id
INNER JOIN (the query above) first_image on first_image.image_venue_id = venues.id
INNER JOIN venue_images on first_image.first_image_id = venue_images.image_id
HAVING
...
I also added one more JOIN, to join the first image id with the actual image. I couldn't check your query but the idea is to procede like this.
Since the query is now becoming more complicated and difficult to mantain, i think it would be better to create a view that extracts the first image for every venue, and then join just the view in your query. This is just an idea. Let me know if it works or if you need any help!
I'm not too sure about your data but a JOIN with the thumbnails table and a group by on your large query would probably work.
GROUP BY venues.id

Get values from database where column is unique

I need help with an advanced SQL-query (MSSQL 2000).
I have a table called Result that lists athletics 100 meter race-times. A runner can have several racetimes but I want to show only the best time from each runner.
The Result-table contains three columns, Result_id, athlete_id, result_time. So athlete_id must be unique when I list the values and result_time must be the fastest (lowest) value.
Any ideas?
In SQL Server 2000, you can't use windows functions. You can do this as follows:
select r.*
from result r join
(select athlete_id, min(result_time) as mintime
from result r
group by athlete_id
) rsum
on rsum.athlete_id = r.athlete_id and r.time = rsum.mintime
In more recent versions of SQL Server, you would use row_number().
If you simply need the fastest time for each athlete_id, do this:
select athelete_id, min(result_time) as FastestTime
from result
group by athelete_id
To show additional columns from the result table, you can join back to it like this:
select r.*
from result r
inner join (
select athelete_id, min(result_time) as FastestTime
from result
group by athelete_id
) rm on r.athelete_id = rm.athelete_id and r.result_time = rm.FastestTime
What you want is to use an aggregate function. in this case min() which will select the minumin data from all the rows that have the same data in the other selected columns. This means you also have to us the group by clause. The query below should give you the results you want.
Edit: If you need other columns, just bring them into the select clause, then add them to the group by clause like below:
select althlete_id, result_id, min(result_time) as result_time from result-table group by althlete_id, result_id
select althlete_id, result_id, min(result_time) as result_time, race_date from result-table group by althlete_id, race_date, result_id
Edit: You need to add all the columns into the group by that aren't part of an aggregate function. Aggregate functions are ones like min(), max(), avg() and so on.
Short answer: If you aren't putting a column in brackets, it probably has to be in the group by.

Categories