SELECT * WHERE val = MIN ( val )? - sql

I'm fairly new to Oracle SQL, but already it's logic is beginning to confuse me. I'm trying to select all columns from a table where a particular column PRICE has the minimum value.
This works:
SELECT MIN(PRICE) FROM my_tab;
This returns me the minimum value. But why can't I select all the columns in that row? The following won't work:
SELECT * FROM my_tab WHERE PRICE = MIN( PRICE );
What am I missing here? Cheers folks!
*EDIT*
Here is the full code I'm having trouble with:
SELECT * FROM ( SELECT c.NAME, o.* FROM customers c JOIN customer_orders o ON c.CUST_NBR = o.CUST_NBR ) AS t WHERE t.PRICE = ( SELECT MIN( t.PRICE) FROM t );

SELECT * FROM TABLE WHERE PRICE = (SELECT MIN(PRICE) FROM TABLE)
--Edited
WITH
TABLE AS
(QUERY)
SELECT * FROM TABLE
WHERE PRICE = (SELECT MIN(PRICE) FROM TABLE)

You can also use a subquery to get the result:
select t1.*
from my_tab t1
inner join
(
SELECT MIN(PRICE) MinPrice
FROM my_tab
) t2
on t1.price = t2.minprice

See previous SO question, and especially answer by "Vash" which is best for your purposes. Note that you probably want to avoid a subselect since Oracle may be smart enough to use an index on the price if available to look at only one record.
Most databases, but apparently not Oracle, have either TOP 1 or LIMIT clauses for questions like these.

Related

Display the max amount and corresponding branch name using max() SQL?

My table would be like
I need an output like:
Just use a subquery:
select * from YourTable
where amount IN (select Max(amount) from YourTable)
SELECT * FROM TableName WHERE Ammount in (SELECT MAX(Ammount) FROM Products );
-OR-
SELECT * FROM TableName ORDER BY Ammount DESC LIMIT 1
select loan_id, branch, amount
from branch
where branch.amount = (select max(s.amount) from branch s)
this will get you multiple rows if multiple branches have the same amount of course.
yea, and the other answer that got posted while I was writing:)

Use column defined in a subquery

Sorry if the title is not clear, I'm a beginner and I didn't know exactly how to formule it...
I have this query working with Oracle :
SELECT
( SELECT COUNT(*)
FROM CATEGORY
) AS NBCATEGORIES,
( SELECT ROUND(AVG(FINANCIALOPERATIONBYPERSON),2)
FROM
(
SELECT SUM(AMOUNT) AS FINANCIALOPERATIONBYPERSON
FROM FINANCIALOPERATION
WHERE PERSONID IS NOT NULL
GROUP BY PERSONID
)
) AS AVERAGELOADAMOUNTBYPERSON
FROM DUAL
I'm looking for the equivalent for Sql Server...
The goal is to have multiple queries in a single query.
So I removed the "FROM DUAL" but I get an error on "FINANCIALOPERATIONBYPERSON" (Invalid column name), certainly because it's defined in the subquery...
How can I modify the query for SQL-Server ?
SQL Server requires aliases for subqueries. So, you can rewrite this as:
SELECT (SELECT COUNT(*)
FROM CATEGORY
) AS NBCATEGORIES,
(SELECT ROUND(AVG(FINANCIALOPERATIONBYPERSON),2)
FROM (SELECT SUM(AMOUNT) AS FINANCIALOPERATIONBYPERSON
FROM FINANCIALOPERATION
WHERE PERSONID IS NOT NULL
GROUP BY PERSONID
) t
) AS AVERAGELOADAMOUNTBYPERSON;
In both databases, though, I would be inclined to write this as:
SELECT c.NBCATEGORIES, ROUND(fo.AVERAGELOADAMOUNTBYPERSON, 2) AS AVERAGELOADAMOUNTBYPERSON
FROM (SELECT COUNT(*) as NBCATEGORIES
FROM CATEGORY c
) c CROSS JOIN
(SELECT SUM(AMOUNT) / COUNT(DISTINCT PERSONID) AS AVERAGELOADAMOUNTBYPERSON
FROM FINANCIALOPERATION fo
WHERE PERSONID IS NOT NULL
) fo;
One note for both these forms: SQL Server does integer arithmetic on integers. So, if AMOUNT is an integer, then you should convert it to an appropriate floating or fixed point numeric type.
You need to add a table alias for the subquery.
SELECT
( SELECT COUNT(*)
FROM CATEGORY
) AS NBCATEGORIES,
( SELECT ROUND(AVG(RESULTS.FINANCIALOPERATIONBYPERSON),2)
FROM
(
SELECT SUM(AMOUNT) AS FINANCIALOPERATIONBYPERSON
FROM FINANCIALOPERATION
WHERE PERSONID IS NOT NULL
GROUP BY PERSONID
) RESULTS
) AS AVERAGELOADAMOUNTBYPERSON

SQL query - percentage of sub sample

I got a SQL statement:
Select
ID, GroupID, Profit
From table
I now want to add a fourth column percentage of group profits.
Therefore the query should sum all the profits for the same group id and then have that number divided by the profit for the unique ID.
Is there a way to do this? The regular sum function does not seem to do the trick.
Thanks
select t1.ID,
t1. GroupID,
(t1.Profit * 1.0) / t2.grp_profit as percentage_profit
from table t1
inner join
(
select GroupID, sum(Profit) as grp_profit
from table
group by GroupID
) t2 on t1.groupid = t2.groupid
One more option with window function
select ID, GroupID, Profit * 1. / SUM(profit) OVER(PARTITION BY GroupID)
from t1
An alternative solution using scalar sub-queries is as follows:
select t1.ID, t1.GroupID, (select sum(t2.Profit) * 1.0 / t1.Profit
from table t2
where t2.GroupID = t1.GroupID) as percentage_profit
from table t1;
To provide an alternate answer, albeit less efficient, is to use a scalar subquery.
SELECT ID, GroupId, Profit, (Profit/(SELECT sum(Profit)
FROM my_table
WHERE GroupId= mt.GroupId))*100 as pct
FROM my_table as mt
From the way it reads I'm not sure if you want "percentage of group profits" or you or want group_profit / individual profit
That's the way this sounds "Therefore the query should sum all the profits for the same group id and then have that number divided by the profit for the unique ID"
Either way just switch the divisor for what you want!
Also if you're using Postgresql >= 8.4 you can use a window function.
SELECT ID, GroupId, Profit, (Profit/ (sum(Profit) OVER(partition by GroupId)))*100 as pct
FROM core_dev.my_table as mt

SQL IN Operator Query

I have a question on the sql IN query. For example you have table with columns id, amount name.
With a query:
SELECT SUM(amount) FROM table WHERE id IN (101,101);
What I want with this is to add amount of a certain id. Whatever the id is inside the IN statement. If like this, two 101, amount of 101 + amount of 101.
The problem is it consider it is one instance. How do I do this? its suppose to be:
SELECT SUM(amount) FROM table WHERE id IN (SELECT id FROM table.........);
Which the sub select return "101, 101".
How
SELECT SUM(tbl.amount)
FROM tbl
JOIN (select 101 id UNION ALL
select 101) InList on InList.id = tbl.id
Expand this way.
I do something like this
Select * From table1
inner join dbo.fnSplit(#ArgList, ',')
That would definitely work for me

Compare SQL groups against eachother

How can one filter a grouped resultset for only those groups that meet some criterion compared against the other groups? For example, only those groups that have the maximum number of constituent records?
I had thought that a subquery as follows should do the trick:
SELECT * FROM (
SELECT *, COUNT(*) AS Records
FROM T
GROUP BY X
) t HAVING Records = MAX(Records);
However the addition of the final HAVING clause results in an empty recordset... what's going on?
In MySQL (Which I assume you are using since you have posted SELECT *, COUNT(*) FROM T GROUP BY X Which would fail in all RDBMS that I know of). You can use:
SELECT T.*
FROM T
INNER JOIN
( SELECT X, COUNT(*) AS Records
FROM T
GROUP BY X
ORDER BY Records DESC
LIMIT 1
) T2
ON T2.X = T.X
This has been tested in MySQL and removes the implicit grouping/aggregation.
If you can use windowed functions and one of TOP/LIMIT with Ties or Common Table expressions it becomes even shorter:
Windowed function + CTE: (MS SQL-Server & PostgreSQL Tested)
WITH CTE AS
( SELECT *, COUNT(*) OVER(PARTITION BY X) AS Records
FROM T
)
SELECT *
FROM CTE
WHERE Records = (SELECT MAX(Records) FROM CTE)
Windowed Function with TOP (MS SQL-Server Tested)
SELECT TOP 1 WITH TIES *
FROM ( SELECT *, COUNT(*) OVER(PARTITION BY X) [Records]
FROM T
)
ORDER BY Records DESC
Lastly, I have never used oracle so apolgies for not adding a solution that works on oracle...
EDIT
My Solution for MySQL did not take into account ties, and my suggestion for a solution to this kind of steps on the toes of what you have said you want to avoid (duplicate subqueries) so I am not sure I can help after all, however just in case it is preferable here is a version that will work as required on your fiddle:
SELECT T.*
FROM T
INNER JOIN
( SELECT X
FROM T
GROUP BY X
HAVING COUNT(*) =
( SELECT COUNT(*) AS Records
FROM T
GROUP BY X
ORDER BY Records DESC
LIMIT 1
)
) T2
ON T2.X = T.X
For the exact question you give, one way to look at it is that you want the group of records where there is no other group that has more records. So if you say
SELECT taxid, COUNT(*) as howMany
GROUP by taxid
You get all counties and their counts
Then you can treat that expressions as a table by making it a subquery, and give it an alias. Below I assign two "copies" of the query the names X and Y and ask for taxids that don't have any more in one table. If there are two with the same number I'd get two or more. Different databases have proprietary syntax, notably TOP and LIMIT, that make this kind of query simpler, easier to understand.
SELECT taxid FROM
(select taxid, count(*) as HowMany from flats
GROUP by taxid) as X
WHERE NOT EXISTS
(
SELECT * from
(
SELECT taxid, count(*) as HowMany FROM
flats
GROUP by taxid
) AS Y
WHERE Y.howmany > X.howmany
)
Try this:
SELECT * FROM (
SELECT *, MAX(Records) as max_records FROM (
SELECT *, COUNT(*) AS Records
FROM T
GROUP BY X
) t
) WHERE Records = max_records
I'm sorry that I can't test the validity of this query right now.