Nested order by/order by within order by in SQL - sql

I am looking to sort my sql results via an sql query with presumably some sort of nested order by/order by within an order by clause
I have the following data:
TERM USER ITEM_NO SCORE
man sam 2 NULL
man sam 1 170
man jerry 1 100
man jerry 2 NULL
man sam 3 NULL
and I wish to obtain the following order for the results:
TERM USER ITEM_NO SCORE
man sam 1 170
man sam 2 NULL
man sam 3 NULL
man jerry 1 100
man jerry 2 NULL
The results must be sorted firstly by the score (stored only in item_no 1 for each user) descending. However any further items created by that user for the seleted term must also be picked up and inserted directly following and in item_no order.
My current query looks like this:
SELECT * FROM table WHERE term = 'man' ORDER BY SCORE DESC, ITEM_NO ASC
...however this simply results as follows:
TERM USER ITEM_NO SCORE
man sam 1 170
man jerry 1 100
man sam 2 NULL
man jerry 2 NULL
man sam 3 NULL
Thank you for any suggestions.

SELECT *,
(SELECT MAX(Score)
FROM TEST t2
WHERE t2.Term = t1.Term AND t2.User = t1.User GROUP BY t2.Term, t2. User) as max_score
FROM test t1
WHERE term = 'man'
ORDER BY max_score DESC, ITEM_NO ASC
Working DEMO
Or another solution with the same results (I think it has better performance, but you'd need to do some testing about that):
SELECT t1.*
FROM test t1
JOIN
(SELECT t2.Term, t2.User, score FROM Test t2 WHERE t2.Item_No = 1) t3
ON t1.Term = t3.Term AND t1.User = t3.User
ORDER BY t3.score DESC, t1.Item_No;
DEMO

select USER, ITEM_NO, SCORE from 'TABLE' order by 2, 3;
-- 2 is Column USER, 3 is Column ITEM_NO

Related

Reconciliation Automation Query

I have one database and time to time i change some part of query as per requirement.
i want to keep record of results of both before and after result of these queries in one table and want to show queries which generate difference.
For Example,
Consider following table
emp_id country salary
---------------------
1 usa 1000
2 uk 2500
3 uk 1200
4 usa 3500
5 usa 4000
6 uk 1100
Now, my before query is :
Before Query:
select count(emp_id) as count,country from table where salary>2000 group by country;
Before Result:
count country
2 usa
1 uk
After Query:
select count(emp_id) as count,country from table where salary<2000 group by country;
After Query Result:
count country
2 uk
1 usa
My Final Result or Table I want is:
column 1 | column 2 | column 3 | column 4 |
2 usa 2 uk
1 uk 1 usa
...... but if query results are same than it shouldn't show in this table.
Thanks in advance.
I believe that you can use the same approach as here.
select t1.*, t2.* -- if you need specific columns without rn than you have to list them here
from
(
select t.*, row_number() over (order by count) rn
from
(
-- query #1
select count(emp_id) as count,country from table where salary>2000 group by country;
) t
) t1
full join
(
select t.*, row_number() over (order by count) rn
from
(
-- query #2
select count(emp_id) as count,country from table where salary<2000 group by country;
) t
) t2 on t1.rn = t2.rn

SQL: Take maximum value, but if a field is missing for a particular ID, ignore all values

This is somewhat difficult to explain...(this is using SQL Assistant for Teradata, which I'm not overly familiar with).
ID creation_date completion_date Difference
123 5/9/2016 5/16/2016 7
123 5/14/2016 5/16/2016 2
456 4/26/2016 4/30/2016 4
456 (null) 4/30/2016 (null)
789 3/25/2016 3/31/2016 6
789 3/1/2016 3/31/2016 30
An ID may have more than one creation_date, but it will always have the same completion_date. If the creation_date is populated for all records for an ID, I want to return the record with the most recent creation_date. However, if ANY creation_date for a given ID is missing, I want to ignore all records associated with this ID.
Given the data above, I would want to return:
ID creation_date completion_date Difference
123 5/14/2016 5/16/2016 2
789 3/25/2016 3/31/2016 6
No records are returned for 456 because the second record has a missing creation_date. The record with the most recent creation_date is returned for 123 and 789.
Any help would be greatly appreciated. Thanks!
Depending on your database, here's one option using row_number to get the max date per group. You can then filter those results with not exists to check against null values:
select *
from (
select *,
row_number() over (partition by id order by creation_date desc) rn
from yourtable
) t
where rn = 1 and not exists (
select 1
from yourtable t2
where t2.creationdate is null and t.id = t2.id
)
row_number is a window function that is supported in many databases. mysql doesn't but you can achieve the same result using user-defined variables.
Here is a more generic version using conditional aggregation:
select t.*
from yourtable t
join (select id, max(creation_date) max_creation_date
from yourtable
group by id
having count(case when creation_date is null then 1 end) = 0
) t2 on t.id = t2.id and t.creation_date = t2.max_creation_date
SQL Fiddle Demo

Get number of different values in a column in Access

I've tried more or less all combinations of count and distinct (except the correct one :) ) in order to get the example below.
Input: table t1
NAME | FOOD
Mary | Apple
Mary | Banana
Mary | Apple
Mary | Strawberry
John | Cherries
Expected output:
NAME | FOOD
Mary | 3
John | 1
N.B. Mary has Apple in two rows but she has 3 as we have 3 different values in the column.
I only managed to get 4 in FOOD Column for her, but I need 3 :(
select a.name as NAME, a.count(name) as Food
from
(SELECT distinct NAME,Food from table)a
Start with a query which gives you unique combinations of NAME and FOOD:
SELECT DISTINCT t1.NAME, t1.FOOD
FROM t1
Then you can use that as a subquery in another where you can GROUP BY and Count:
SELECT sub.NAME, Count(*) AS [FOOD]
FROM
(
SELECT DISTINCT t1.NAME, t1.FOOD
FROM t1
) AS sub
GROUP BY sub.NAME;
select a.name, sum(a.FoodCount) from(
select distinct name,COUNT(food) as FoodCount from #t1 group by name, food ) as a group by a.name order by 2 desc

How to query the three best players in Oracle?

I have the following table:
NAME | SCORE
ALICE | 100
BOB | 90
CHARLES| 90
DUKE | 80
EVE | 70
...
My question is the following:
How can I extract with one query the name of the three best players? In my example the query should return four rows (ALICE, BOB, CHARLES and DUKE) because there are two silver medalists (they both have 90 points).
Thank You in advance.
Oracle has the DENSE_RANK analytical function for that exact purpose:
select name, score from (
select name, score, dense_rank() over(order by score desc nulls last) rank
-- ^^^^^^^^^^
-- reject NULL score at the end
from t
) V
where rank < 4
order by rank, name
See http://sqlfiddle.com/#!4/88445/5
How about the following
select *
from table1
where score >=
(select score from (
select score, rownum r from (
select distinct score from table1 order by score desc
) where rownum <= 3
) where r = 3)
order by score desc
See also this SQLFiddle: http://sqlfiddle.com/#!4/23e68/1

Get values and like values in SQL

I have a SQL table that contains the following
ID AccountNumber Name
1 12345 Tony
2 123456 Mike
3 123458 Mike
4 45689 Tom
5 666999 Tim
6 6669997 Lisa
7 44455 Tim
8 78901 Matt
9 789011 Roger
What I need to do is show me all records where the Account Number begin with the same value (indeterminate number). For example. In this table, I'd want to select and display the following:
12345
123456
123458
666999
6669997
78901
789011
As you can see, it shows the each row where the AccountNumber matches or has the same beginning number. I haven't been able to find the proper query and would love any help.
Thanks!
The cases that you mention satisfy that the longer starts with the shorter. Here is a query that will get the shortest match for each account number:
select AccountNumber
from (select a.*, count(*) over (partition by ShortestAN) as numAN
from (select a.*,
(select top 1 a2.AccountNumber
from accounts a2
where a.AccountNumber like a2.AccountNumber + '%'
order by length(a2.AccountNumber) asc
) as ShortestAN
from accounts a
) a
) a
where numAN > 1
order by ShortestAN, AccountNumber;
The subquery finds the shortest account number that matches. The rest is just returning the ones where there is more than one match.
select a1.ID, a1.AccountNumber, a1.Name,
a2.ID, a2.AccountNumber, a2.Name
from Accounts a1
join Accounts a2 on LEN(a1.name) <= LEN(a2.name) and SUBSTRING(a2.name, 1, LEN(a1.name)) = a1.name
where /*are not same rows*/ a1.ID <> a2.ID
Would not an order by work if it were ordering as String?
SELECT AccountNumber, Id, Name
FROM Accounts
ORDER BY CAST(AccountNumber AS NVARCHAR(50))