Say, I have 3 columns in my table :
---------------
name | ID | Amt
ABC | 1 | 500
ABC | 1 | 650
XYZ | 2 | 700
XYZ | 2 | 550
DEF | 3 | 200
how can I get an output where the amount is aggregated for each ID, i.e.,
ABC gives 1150, XYZ 1250 and DEF 200?
You want a group by, with what sounds like a sum from your example:
Select Name, ID, sum(amt) as TotalAmt
from MyTable
Group by Name, ID
SELECT name,SUM(Amt) FROM [table] GROUP BY name
or, if you want to display name and ID
SELECT name,ID,SUM(Amt) OVER (PARTITION BY name) FROM [table]
This could be done using a simple group by statement:
select name,
id,
sum(amt) as agg_sum
from total
group by name,id;
SQL Fiddle Demo
Related
I have an sql table with the below data:
Id department Amount
1 Accounting 10000
2 Catering 5000
3 Cleaning 5000
I want to return the data as below:
Id department Amount
1 Accounting 10000
1 50%
2 Catering 5000
2 25%
3 Cleaning 5000
3 25%
This implies every records return a second record just below it and display the percentage of the total amount. I have tried to use a PIVOT table but still I cannot position
the second row just below the first related one.
Has anyone ever done something similar I need just some guidelines.
create table #T(Id int, Dept varchar(10),Amount int)
insert into #T
values(1,'Accounting',10000),(2,'Catering',5000),(3,'Cleaning',5000)
declare #Totll float = (Select sum(Amount) from #T)
Select *
from #T
union
select Id,Convert(varchar(50), (Amount/#Totll)*100)+'%',0
from #T
order by Id,Amount desc
Use a CTE to calculate the total of the amounts.
Then use UNION ALL for your table and the query which calculates the percentages:
with cte as (select sum(amount) sumamount from tablename)
select id, department, amount
from tablename
union all
select id, concat(100 * amount / (select sumamount from cte), '%'), null
from tablename
order by id, amount desc
See the demo.
Results:
> id | department | amount
> -: | :--------- | -----:
> 1 | Accounting | 10000
> 1 | 50% | null
> 2 | Catering | 5000
> 2 | 25% | null
> 3 | Cleaning | 5000
> 3 | 25% | null
I am trying to return the first registration for a person based on the minimum registration date and then return full information. The data looks something like this:
Warehouse_ID SourceID firstName lastName firstProgramSource firstProgramName firstProgramCreatedDate totalPaid totalRegistrations
12345 1 Max Smith League Kid Hockey 2017-06-06 $100 3
12345 6 Max Smith Activity Figure Skating 2018-09-26 $35 1
The end goal is to return one row per person that looks like this:
Warehouse_ID SourceID firstName lastName firstProgramSource firstProgramName firstProgramCreatedDate totalPaid totalRegistrations
12345 1 Max Smith League Kid Hockey 2017-06-06 $135 4
So, this would aggregate the totalPaid and totalRegistrations variables based on the Warehouse_ID and would pull the rest of the information based on the min(firstProgramCreatedDate) specific to the Warehouse_ID.
This will end up in Tableau, so what I've recently tried ignores aggregating totalPaid and totalRegistrations for now (I can get that in another query pretty easily). The query I'm using seems to work, but it is taking forever to run; it seems to be going row by row for >50,000 rows, which is taking forever.
select M.*
from (
select Warehouse_ID, min(FirstProgramCreatedDate) First
from vw_FirstRegistration
group by Warehouse_ID
) B
left join vw_FirstRegistration M on B.Warehouse_ID = M.Warehouse_ID
where B.First in (M.FirstProgramCreatedDate)
order by B.Warehouse_ID
Any advice on how I can achieve my goal without this query taking an hour plus to run?
A combination of the ROW_NUMBER windowing function, plus the OVER clause on a SUM expression should perform pretty well.
Here's the query:
SELECT TOP (1) WITH TIES
v.Warehouse_ID
,v.SourceID
,v.firstName
,v.lastName
,v.firstProgramSource
,v.firstProgramName
,v.firstProgramCreatedDate
,SUM(v.totalPaid) OVER (PARTITION BY v.Warehouse_ID) AS totalPaid
,SUM(v.totalRegistrations) OVER (PARTITION BY v.Warehouse_ID) AS totalRegistrations
FROM
#vw_FirstRegistration AS v
ORDER BY
ROW_NUMBER() OVER (PARTITION BY v.Warehouse_ID
ORDER BY CASE WHEN v.firstProgramCreatedDate IS NULL THEN 1 ELSE 0 END,
v.firstProgramCreatedDate)
And here's a Rextester demo: https://rextester.com/GNOB14793
Results (I added another kid...):
+--------------+----------+-----------+----------+--------------------+------------------+-------------------------+-----------+--------------------+
| Warehouse_ID | SourceID | firstName | lastName | firstProgramSource | firstProgramName | firstProgramCreatedDate | totalPaid | totalRegistrations |
+--------------+----------+-----------+----------+--------------------+------------------+-------------------------+-----------+--------------------+
| 12345 | 1 | Max | Smith | League | Kid Hockey | 2017-06-06 | 135.00 | 4 |
| 12346 | 6 | Joe | Jones | Activity | Other Activity | 2017-09-26 | 125.00 | 4 |
+--------------+----------+-----------+----------+--------------------+------------------+-------------------------+-----------+--------------------+
EDIT: Changed the ORDER BY based on comments.
Try to use ROW_NUMBER() with PARTITIYION BY.
For more information please refer to:
https://learn.microsoft.com/en-us/sql/t-sql/functions/row-number-transact-sql?view=sql-server-2017
I've written the following query:
SELECT [User], count(*) as Records
FROM dbo.PBBuilds
GROUP BY [User]
ORDER BY [Records] DESC
It selects a USERID and counts the amount or rows associated as 'records'.
--------------------------------------------------
| Users | records |
------------------------------------------------- |
| 0ca3f535-96f2-4926-9b4d-25fb2aa713eb | 3 |
| a32d1784-d636-4caf-bb9d-60bfbfc1aadf | 2 |
| 5fabb0aa-f61f-4180-90f6-5dd1650fd0db | 1 |
---------------------------------------------------
The Users column relates to an ID column in another table where the users name is stored. How can I retrieve and match the data by this link?
Assuming your other table is called other_table and also has the ID in column User, then:
SELECT UserName, COUNT(*) Records
FROM dbo.PBBuilds b INNER JOIN other_table o
on b.User = o.User
GROUP BY UserName
ORDER BY COUNT(*) DESC
I have following table:
ID | source | Name | Age | ... | ...
1 | SQL | John | 18 | ... | ...
2 | SAP | Mike | 21 | ... | ...
2 | SQL | Mike | 20 | ... | ...
3 | SAP | Jill | 25 | ... | ...
I want to have one record for each ID. The idea behind this is that if the ID comes only once (no matter the Source), that record will be taken. But, If there are 2 records for one ID, the one containing SQL as source will be the used record here.
So, In this case, the result will be:
ID | source | Name | Age | ... | ...
1 | SQL | John | 18 | ... | ...
2 | SQL | Mike | 20 | ... | ...
3 | SAP | Jill | 25 | ... | ...
I did this with a partition over (ordered by Source desc), but that wouldn't work well if a third source will be added one day.
Any other options/ideas?
The easiest approach(in my opinion) is using a CTE with a ranking function:
with cte as
(
select ID, source, Name, Age, ... ,
rn = row_number() over (partition by ID order by case when source = 'sql'
then 0 else 1 end asc)
from dbo.tablename
)
select ID, source, Name, Age, ...
from cte
where rn = 1
You can use ROW_NUMBER:
WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER( PARTITION BY ID
ORDER BY CASE WHEN [Source] = 'SQL' THEN 1 ELSE 2 END)
FROM dbo.YourTable
)
SELECT *
FROM CTE
WHERE RN = 1;
You can use the WITH TIES clause and the window function Row_Number()
Select Top 1 With Ties *
From YourTable
Order By Row_Number() over (Partition By ID Order By Case When Source = 'SQL' Then 0 Else 1 End)
How about
SELECT *
FROM table
WHERE ID in (
SELECT ID FROM test
group by ID
having count(ID) = 1)
OR source = 'SQL'
I have a postgres database with duplicated entries on one of the table. I would like to show the created_by columns
Table1
id | number
1 | 123
2 | 124
3 | 125
4 | 126
Table2
id | number | created_on
1 | 123 | 3/29
2 | 123 | 4/3
3 | 124 | 3/31
4 | 124 | 4/1
On table 2 number are duplicated. I would like to form a single query to list the following:
id | number | created_on
1 | 123 | 4/3
2 | 124 | 4/1
For duplicated entries only the latest entry will be included. How could I form that SQL query?
SELECT DISTINCT ON (Table1.number) Table1.id, Table2.number, Table2.create_on FROM Table1
JOIN Table2 ON Table1.number=Table2.number
ORDER BY Table2.create_on;
Actually I tried putting 'DISTINCT ON' and 'ORDER BY' in a single query (with JOIN) it gives me the following error:
SELECT DISTINCT ON expressions must match initial ORDER BY expressions
The columns in DISTINCT ON() have to be the first ones in the ORDER BY query, also if you want the latest created_on date you should order by created_on DESC
SELECT DISTINCT ON (Table1.number) Table1.id, Table2.number, Table2.created_on
FROM Table1
JOIN Table2
ON Table1.number=Table2.number
ORDER BY Table1.number,Table2.created_on DESC;
http://sqlfiddle.com/#!12/5538a/2
As you said in the comment: created_on=date_trunc('day', now()), so the data type of the field created_on is timestamp. Here is what you can do:
SELECT table_1.id, table_1.number, max(created_on) as created_on
FROM table_1
inner join table_2 using(number)
group by table_1.id, table_1.number