Selecting specific data based on multiple conditions - sql

I need some help constructing a SQL command for a database query. The database has 5 columns:
Date(string)
Name(string)
number(int)
There can be multiple entries for each date, name, and number.
I want to SELECT only one row for each date and name combination. The problem is there are multiple instances of these. For each date and name combination I want to select the one with the highest number. I would like it ordered by date. For example:
date | name | number
1/1/1 henry 500
1/1/1 henry 2000
1/1/1 jacob 5
1/1/1 jacob 8
1/2/1 henry 6
The command would return:
1/1/1 henry 2000
1/1/1 jacob 8
1/2/1 henry 6
I have been messing around with some commands but I am a pretty lost. Is this even possible?

You can use ROW_NUMBER:
WITH cte
AS (SELECT date,
name,
number,
rn = Row_number ()
OVER(
partition BY date, name
ORDER BY number DESC)
FROM dbo.tablename)
SELECT date,
name,
number
FROM CTE
WHERE rn = 1
ORDER BY date ASC
DEMO
ROW_NUMBER will always select one record per group. If you want to get all rows with the highest number for a given name(if there are more than one) use DENSE_RANK instead.

SELECT date, name, MAX(number)
FROM Table1
GROUP BY date, name
ORDER date, name

Try grouping by date and name and then selecting the maximum number. Like so (exact syntax may vary depending on your version of sql):
select
date,
name,
max(number)
from
yourtable
group by
date,
name
order by
date asc

Related

Finding the first occurrence of an element in a SQL database

I have a table with a column for customer names, a column for purchase amount, and a column for the date of the purchase. Is there an easy way I can find how much first time customers spent on each day?
So I have
Name | Purchase Amount | Date
Joe 10 9/1/2014
Tom 27 9/1/2014
Dave 36 9/1/2014
Tom 7 9/2/2014
Diane 10 9/3/2014
Larry 12 9/3/2014
Dave 14 9/5/2014
Jerry 16 9/6/2014
And I would like something like
Date | Total first Time Purchase
9/1/2014 73
9/3/2014 22
9/6/2014 16
Can anyone help me out with this?
The following is standard SQL and works on nearly all DBMS
select date,
sum(purchaseamount) as total_first_time_purchase
from (
select date,
purchaseamount,
row_number() over (partition by name order by date) as rn
from the_table
) t
where rn = 1
group by date;
The derived table (the inner select) selects all "first time" purchases and the outside the aggregates based on the date.
The two key concepts here are aggregates and sub-queries, and the details of which dbms you're using may change the exact implementation, but the basic concept is the same.
For each name, determine they're first date
Using the results of 1, find each person's first day purchase amount
Using the results of 2, sum the amounts for each date
In SQL Server, it could look like this:
select Date, [totalFirstTimePurchases] = sum(PurchaseAmount)
from (
select t.Date, t.PurchaseAmount, t.Name
from table1 t
join (
select Name, [firstDate] = min(Date)
from table1
group by Name
) f on t.Name=f.Name and t.Date=f.firstDate
) ftp
group by Date
If you are using SQL Server you can accomplish this with either sub-queries or CTEs (Common Table Expressions). Since there is already an answer with sub-queries, here is the CTE version.
First the following will identify each row where there is a first time purchase and then get the sum of those values grouped by date:
;WITH cte
AS (
SELECT [Name]
,PurchaseAmount
,[date]
,ROW_NUMBER() OVER (
PARTITION BY [Name] ORDER BY [date] --start at 1 for each name at the earliest date and count up, reset every time the name changes
) AS rn
FROM yourTableName
)
SELECT [date]
,sum(PurchaseAmount) AS TotalFirstTimePurchases
FROM cte
WHERE rn = 1
GROUP BY [date]

select distinct of a column and order by date column but without showing the date column

The following simple query will return result with name and date which is order by date.
SELECT DISTINCT Name, Date
FROM dbo.Table WITH(NOLOCK)
ORDER BY DATE
Result
Name | Date
--------------------
a | 31-Jul-2013
a | 31-Aug-2013
a | 30-Sep-2013
b | 31-Oct-2013
b | 30-Nov-2013
a | 31-Dec-2013
How can i select distinct only the Name but the sequence of the Name must be order by date?
New result
Name
a
b
a
Try this query:
WITH Names AS (
SELECT
Name,
Seq = Dense_Rank() OVER (ORDER BY SomeDate)
- Dense_Rank() OVER (PARTITION BY Name ORDER BY SomeDate)
FROM
dbo.Names
)
SELECT Name
FROM Names
GROUP BY Name, Seq
ORDER BY Min(Seq)
;
Run this live in a SQL Fiddle
This will return the A, B, A pattern you requested.
You can't use a simple DISTINCT because you're asking to display a single value, but order by all the dates that the value may have associated with it. What if your data looks like this?
Name Date
---- ----
A 2014-01-01
B 2014-02-01
B 2014-03-01
A 2014-04-01
How do you decide whether to put A first, or B first, based one some theoretical ordering by the date?
That is why I had to do the above subtraction of windowing functions, which should order things how you want.
Notes
I call this technique a "simulated PREORDER BY". Dense_Rank does not offer any way to preorder the rows before ranking based on ordering. If you could do Dense_Rank() OVER (PREORDER BY Date ORDER BY Name) to indicate that you want to order by Date first, but don't want it to be part of the resulting rank calculation, you'd be set! However, that doesn't exist. After some study a while back I hit on the idea to use a combination of windowing functions to accomplish the purpose, and the above query represents that result.
Note that you must also GROUP BY the Name, not just the resulting subtracted windowing expressions, in order for everything to work correctly, because the expression, while unique to the other column (in this case, Name), can result in duplicate values across the entire set (two different value Names can have the same expression result). You can assign a new rank or other windowing function if there is a desire for a value that can be ordered by individually.
I think a common table expression (CTE) will work here:
with cte as(
SELECT DISTINCT Name, Date
FROM dbo.Table WITH(NOLOCK)
ORDER BY DATE
)
select Name
from cte
order by Date

SQL Query to obtain the maximum value for each unique value in another column

ID Sum Name
a 10 Joe
a 8 Mary
b 21 Kate
b 110 Casey
b 67 Pierce
What would you recommend as the best way to
obtain for each ID the name that corresponds to the largest sum (grouping by ID).
What I tried so far:
select ID, SUM(Sum) s, Name
from Table1
group by ID, Name
Order by SUM(Sum) DESC;
this will arrange the records into groups that have the highest sum first. Then I have to somehow flag those records and keep only those. Any tips or pointers? Thanks a lot
In the end I'd like to obtain:
a 10 Joe
b 110 Casey
You want the row_number() function:
select id, [sum], name
from (select t.*]
row_number() over (partition by id order by [sum] desc) as seqnum
from table1
) t
where seqnum = 1;
Your question is more confusing than it needs to be because you have a column called sum. You should avoid using SQL reserved words for identifiers.
The row_number() function assigns a sequential number to a group of rows, starting with 1. The group is defined by the partition by clause. In this case, all rows with the same id are in the same group. The ordering of the numbers is determined by the order by clause, so the one with the largest value of sum gets the value of 1.
If you might have duplicate maximum values and you want all of them, use the related function rank() or dense_rank().
select *
from
(
select *
,rn = row_number() over (partition by Id order by sum desc)
from table
)x
where x.rn=1
demo

Select a column with condition with other column as it is

I have not searched a lot before asking because I am feeling the search string complicated to write.
I will ask by example instead of description.
I have a table called user_sale
id emp_id emp_name emp_location date sales
------------------------------------------------------
1 111 mr.one A 2013/07/17 5000
2 111 mr.one C 2013/07/14 6000
3 222 mr.two B 2013/06/15 5500
and so on.
In output I want all field as it is but want emp_location latest within a month.
I am able to get month and year from date. So I can do group by year and month.
expected output:
id emp_id emp_name emp_location date sales
------------------------------------------------------
1 111 mr.one A 2013/07/17 5000
2 111 mr.one A 2013/07/14 6000
3 222 mr.two B 2013/06/15 5500
One solution is to join with the same table, but since the table contains large data it does not seem like a proper solution.
Use the window function first_value() to get the "first" of one column (emp_location) as defined by another column (date), embedded in otherwise unchanged rows:
SELECT id, emp_id, emp_name
, first_value(emp_location) OVER (PARTITION BY emp_id
ORDER BY date DESC) AS emp_location
, date, sales
FROM user_sale
ORDER BY id;
Assuming that emp_id is unique per group as you define it.
Aside: you shouldn't be using date (reserved word in SQL standard) or id (non-descriptive) as column names.
You can use a windowing function, like this to get the latest data for each employee:
SELECT *
FROM
(SELECT *,
row_number() OVER (PARTITION BY emp_name ORDER BY date_sales DESC) AS pos
FROM user_sale
) AS rankem
WHERE pos = 1;
I'm not quite clear what exactly you want but I imagine you can join to that sub-query to get what you need.

Return min date and corresponding amount to that distinct ID

Afternoon
I am trying to return the min value/ max values in SQL Server 2005 when I have multiple dates that are the same but the values in the Owed column are all different. I've already filtered the table down by my select statement into a temp table for a different query, when I've then tried to mirror I have all the duplicated dates that you can see below.
I now have a table that looks like:
ID| Date |Owes
-----------------
1 20110901 89
1 20110901 179
1 20110901 101
1 20110901 197
1 20110901 510
2 20111001 10
2 20111001 211
2 20111001 214
2 20111001 669
My current query:
Drop Table #Temp
Select Distinct Convert(Varchar(8), DateAdd(dd, Datediff(DD,0,DateDue),0),112)as Date
,ID
,Paid
Into #Temp
From Table
Where Paid <> '0'
Select ,Id
,Date
,Max(Owed)
,Min(Owed)
From #Temp
Group by ID, Date, Paid
Order By ID, Date, Paid
This doesn't strip out any of my dates that are the same, I'm new to SQL but I'm presuming its because my owed column has different values. I basically want to be able to pull back the first record as this will always be my minimum paid and my last record will always be my maximum owed to work out my total owed by ID.
I'm new to SQL so would like to understand what I've done wrong for my future knowledge of structuring queries?
Many Thanks
In your "select into"statement, you don't have an Owed column?
GROUP BY is the normal way you "strip out values that are the same". If you group by ID and Date, you will get one row in your result for each distinct pair of values in those two columns. Each row in the results represents ALL the rows in the underlying table, and aggregate functions like MIN, MAX, etc. can pull out values.
SELECT id, date, MAX(owes) as MaxOwes, MIN(owes) as minOwes
FROM myFavoriteTable
GROUP BY id, date
In SQL Server 2005 there are "windowing functions" that allow you to use aggregate functions on groups of records, without grouping. An example below. You will get one row for each row in the table:
SELECT id, date, owes,
MAX(Owes) over (PARTITION BY select, id) AS MaxOwes,
MIN(Owes) over (PARTITION BY select, id) AS MinOwes
FROM myfavoriteTable
If you name a column "MinOwes" it might sound like you're just fishing tho.
If you want to group by date you can't also group by ID, too, because ID is probably unique. Try:
Select ,Date
,Min(Owed) AS min_date
,Max(Owed) AS max_date
From #Temp
Group by Date
Order By Date
To get additional values from the row (your question is a bit vague there), you could utilize window functions:
SELECT DISTINCT
,Date
,first_value(ID) OVER (PARTITION BY Date ORDER BY Owed) AS min_owed_ID
,last_value(ID) OVER (PARTITION BY Date ORDER BY Owed) AS max_owed_ID
,first_value(Owed) OVER (PARTITION BY Date ORDER BY Owed) AS min_owed
,last_value(Owed) OVER (PARTITION BY Date ORDER BY Owed) AS max_owed
FROM #Temp
ORDER BY Date;