Distinct two columns and sum a third column - sql-server

I have the next table, is called: mytable:
---------------------------------
|id | date | name|actionCount |
---------------------------------
|a1 |03.03.12| ba | 12 |
|a3 |06.02.13| ba | 7 |
|a1 |06.02.13| ca | 2 |
|a3 |06.02.13| ba | 9 |
|a1 |06.06.13| ba | 2 |
|--------------------------------
I want to get the distinct id and name, and sum them count.
so I have to get:
------------------------
|id | name|actionCount |
------------------------
|a1 | ba | 14 |
|a3 | ba | 16 |
|a1 | ca | 2 |
------------------------
I tried:
SELECT DISTINCT id,name,SUM(actionCount) FROM mytable GROUP BY actionCount
but I got:
Column 'mytable.id' is invalid in the select list because it is not contained in either
an aggregate function or the GROUP BY clause.
Any help appreciated!

You can try like this...
SELECT id,name,SUM(actionCount) FROM mytable GROUP BY id,name

Related

Results of join listed in rows vs additional columns?

I have 2 tables, with the same exact fields and fields names. i am trying to inner join them but im having some difficulty determining how i can get my results in my desired format.
I know i can do select a.customer, a.id, a.date, a.line, a.product, b.customer, b.id, b.date, b.line, b.product but instead of having my A data and B data on the same row, id like for them to be on seperate rows.
I have 2 tables, with the same exact fields and fields names, i am trying to inner join them so that unique line becomes a row.
Table A:
|customer| id | Date | line | Product|
|--------|-----|---------|------|--------|
| 445678 | 123 | 1/1/22 | 10 | 88975 |
| 853652 | 456 | 1/10/22 | 5 | 55876 |
| 845689 | 789 | 1/25/22 | 1 | 45587 |
TABLE B:
|customer| id | Date | line | Product|
|--------|-----|---------|------|--------|
| 445678 | 489 | 1/1/22 | 1 | 87574 |
| 853652 | 853 | 1/10/22 | 12 | 45678 |
| 587435 | 157 | 2/12/22 | 3 | 25896 |
DESIRED RESULTS:
|customer| id | Date | line | Product|
|--------|-----|---------|------|--------|
| 445678 | 123 | 1/1/22 | 10 | 88975 |
| 445678 | 489 | 1/1/22 | 1 | 87574 |
| 853652 | 456 | 1/10/22 | 5 | 55876 |
| 853652 | 853 | 1/10/22 | 12 | 45678 |
my query:
select a.customer, a.id, a.date, a.line, a.product
from data1 a
inner join data2 b
on a.date = b.date
and a.customer = b.customer

Pivoting Data in SQL and Updting it into Destination Table

I am working on a Store Procedure where I need to update records from from table 1 into table 2.
Table1: contains the following 4 columns
----------------------------------------------
| ID | TableName | ColumnName | Value |
----------------------------------------------
| 1 | [UserDetails] | [FinalScore] | 92 |
| 2 | [UserDetails] | [FinalScore] | 89 |
| 3 | [UserDetails] | [FinalScore] | 65 |
| 4 | [UserDetails] | [FinalScore] | 91 |
| 5 | [UserDetails] | [FinalScore] | 76 |
| 1 |[EmployeeDetail]| [ScoreData] | 0.91 |
----------------------------------------------
UserDetails table
-----------------------------------------------------------
| UserID | UserName | ContactNo | FinalScore |
-----------------------------------------------------------
| 1 | John G | +13288992342 | 0 |
| 2 | Leonard J | +14581232342 | 0 |
| 3 | Max R | +17123992342 | 0 |
| 4 | Robert H | +15688992122 | 0 |
| 5 | Jimmy L | +1328996782 | 0 |
-----------------------------------------------------------
Need to load all the data from table1 into the corresponding destination table for large amount of data (30,000 to 60,000) records.
Table1 contains the ID (from ID Column in table1) and FinalScore (from ColumnName Column in table1) in the destination table (from TableName Column in table1) where the value (from Value Column in table1) needs to be loaded.
End Result of UserDetails table after SP execution :
-----------------------------------------------------------
| UserID | UserName | ContactNo | FinalScore |
-----------------------------------------------------------
| 1 | John G | +13288992342 | 92 |
| 2 | Leonard J | +14581232342 | 89 |
| 3 | Max R | +17123992342 | 65 |
| 4 | Robert H | +15688992122 | 91 |
| 5 | Jimmy L | +1328996782 | 76 |
-----------------------------------------------------------
I am not sure how to load the data from "table1" into destination table (userdetails table) for bulk data as update query in a loop is taking very long time to complete.
It's not pivot what you're after but a simple join:
select
a.userid, a.contactno, b.finalscore
from UserDetails a
join table1 b on a.id = b.id
alternatively, if you want to update the old table without creating a new one, you can update join
SQL update query using joins

TSQL-JOIN: display non-existing values in one table as zero in Join

I have two tables:
ProjectProduct (two IDs for project and product) and
ProductStatus (which contains quality ratings for products).
Table: ProjectProduct
| productID | projectID |
| --------- | --------- |
| 39 | 26 |
| 40 | 26 |
| 41 | 26 |
| 42 | 26 |
Table: ProductStatus
| id | projectID | productID | typeID | Status | Comment | RatedBy |
| --- | --------- | --------- | ------ | ------ | ------------ | ------- |
| 1 | 26 | 39 | 2 | 30 | comm1 | 0 |
| 2 | 26 | 39 | 2 | 70 | comm2 | 0 |
| 22 | 26 | 39 | 1 | 70 | diff type | 0 |
| 3 | 26 | 39 | 2 | 100 | comm3 | 0 |
| 4 | 26 | 39 | 2 | 70 | diff ratedBy | 1 |
| 5 | 26 | 39 | 2 | 100 | comm5 | 0 |
| 6 | 26 | 39 | 2 | 30 | comm6 | 0 |
I need to join those two tables so that every product in the ProjectProduct table will display a Status value even if there is no corosponding entry in the ProductStatus table.
In above example only productID 39 exists in both tables. To show all productIDs the output should contain a zero value in the Status column for productIDs 40 to 42.
This is the part that I cannot figure out. For example the ProductStatus TypeID can contain 1 or 2. TypeID 2 has to be distinguished between RatedBy which can contain 0 or 1. Do I need the table or select statement to reflect all possible permutations?
Also only the row with the highest ID grouped by projectID, productID, typeID, RatedBy should be picked where there is an existing rating.
Desired output:
I also created a SQL Fiddle
I hope you can guide me in the right direction.
Thank you.
Query
SELECT ProjectProduct.projectID, ProjectProduct.productID, ProductStatus.typeid,ProductStatus.status,ProductStatus.Comment,ProductStatus.ratedBY
FROM ProjectProduct
left join
(
SELECT max(ID) id, productID,projectID
FROM ProductStatus
where typeID = 2
and ratedBY = 0
group BY productID,projectID ) maxproduct on ProjectProduct.productID = maxproduct.productID and ProjectProduct.projectID = maxproduct.projectID
left join ProductStatus on ProductStatus.id = maxproduct.ID
Output
you can use temp table like that:
select Max(Id) maxID ,ProductId,ProjectId into #Temp1 from ProductStatus
where typeID=2 and RatedBy=0
group by ProductId,ProjectId
select * into #Temp2 from ProductStatus where Id In (select MaxId from #Temp1)
select p.ProjectId,p.ProductId, 2 as typeID,isnull(t.status,0) as Status,t.Comment,0 as RatedBy
from ProjectProduct p left join #Temp2 t on p.ProductId=t.ProductId and p.ProjectId=t.ProjectId

Where to use Outer Apply

MASTER TABLE
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
DETAILS TABLE
x------x--------------------x-------x
| Id | PERIOD | QTY |
x------x--------------------x-------x
| 1 | 2014-01-13 | 10 |
| 1 | 2014-01-11 | 15 |
| 1 | 2014-01-12 | 20 |
| 2 | 2014-01-06 | 30 |
| 2 | 2014-01-08 | 40 |
x------x--------------------x-------x
I am getting the same results when LEFT JOIN and OUTER APPLY is used.
LEFT JOIN
SELECT T1.ID,T1.NAME,T2.PERIOD,T2.QTY
FROM MASTER T1
LEFT JOIN DETAILS T2 ON T1.ID=T2.ID
OUTER APPLY
SELECT T1.ID,T1.NAME,TAB.PERIOD,TAB.QTY
FROM MASTER T1
OUTER APPLY
(
SELECT ID,PERIOD,QTY
FROM DETAILS T2
WHERE T1.ID=T2.ID
)TAB
Where should I use LEFT JOIN AND where should I use OUTER APPLY
A LEFT JOIN should be replaced with OUTER APPLY in the following situations.
1. If we want to join two tables based on TOP n results
Consider if we need to select Id and Name from Master and last two dates for each Id from Details table.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
LEFT JOIN
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
ORDER BY CAST(PERIOD AS DATE)DESC
)D
ON M.ID=D.ID
which forms the following result
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | NULL | NULL |
| 3 | C | NULL | NULL |
x------x---------x--------------x-------x
This will bring wrong results ie, it will bring only latest two dates data from Details table irrespective of Id even though we join with Id. So the proper solution is using OUTER APPLY.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
OUTER APPLY
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
WHERE M.ID=D.ID
ORDER BY CAST(PERIOD AS DATE)DESC
)D
Here is the working : In LEFT JOIN , TOP 2 dates will be joined to the MASTER only after executing the query inside derived table D. In OUTER APPLY, it uses joining WHERE M.ID=D.ID inside the OUTER APPLY, so that each ID in Master will be joined with TOP 2 dates which will bring the following result.
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-08 | 40 |
| 2 | B | 2014-01-06 | 30 |
| 3 | C | NULL | NULL |
x------x---------x--------------x-------x
2. When we need LEFT JOIN functionality using functions.
OUTER APPLY can be used as a replacement with LEFT JOIN when we need to get result from Master table and a function.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
And the function goes here.
CREATE FUNCTION FnGetQty
(
#Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=#Id
)
which generated the following result
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-11 | 15 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-06 | 30 |
| 2 | B | 2014-01-08 | 40 |
| 3 | C | NULL | NULL |
x------x---------x--------------x-------x
3. Retain NULL values when unpivoting
Consider you have the below table
x------x-------------x--------------x
| Id | FROMDATE | TODATE |
x------x-------------x--------------x
| 1 | 2014-01-11 | 2014-01-13 |
| 1 | 2014-02-23 | 2014-02-27 |
| 2 | 2014-05-06 | 2014-05-30 |
| 3 | NULL | NULL |
x------x-------------x--------------x
When you use UNPIVOT to bring FROMDATE AND TODATE to one column, it will eliminate NULL values by default.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
which generates the below result. Note that we have missed the record of Id number 3
x------x-------------x
| Id | DATES |
x------x-------------x
| 1 | 2014-01-11 |
| 1 | 2014-01-13 |
| 1 | 2014-02-23 |
| 1 | 2014-02-27 |
| 2 | 2014-05-06 |
| 2 | 2014-05-30 |
x------x-------------x
In such cases an APPLY can be used(either CROSS APPLY or OUTER APPLY, which is interchangeable).
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
which forms the following result and retains Id where its value is 3
x------x-------------x
| Id | DATES |
x------x-------------x
| 1 | 2014-01-11 |
| 1 | 2014-01-13 |
| 1 | 2014-02-23 |
| 1 | 2014-02-27 |
| 2 | 2014-05-06 |
| 2 | 2014-05-30 |
| 3 | NULL |
x------x-------------x
In your example queries the results are indeed the same.
But OUTER APPLY can do more: For each outer row you can produce an arbitrary inner result set. For example you can join the TOP 1 ORDER BY ... row. A LEFT JOIN can't do that.
The computation of the inner result set can reference outer columns (like your example did).
OUTER APPLY is strictly more powerful than LEFT JOIN. This is easy to see because each LEFT JOIN can be rewritten to an OUTER APPLY just like you did. It's syntax is more verbose, though.

Twice Inner Join on same table with Aggregate function

being a novice sql user:
I have a simple table storing some records over night daily. table:
Table: T1
+----+-----+----+-----------+------------+
| Id | A | AB | Value | Date |
+----+-----+----+-----------+------------+
| 1 | abc | I | -48936.08 | 2013-06-24 |
| 2 | def | A | 431266.19 | 2013-06-24 |
| 3 | xyz | I | -13523.90 | 2013-06-24 |
| 4 | abc | A | 13523.90 | 2013-06-23 |
| 5 | xyz | I | -13523.90 | 2013-06-23 |
| 6 | def | A | 13523.90 | 2013-06-22 |
| 7 | def | I | -13523.90 | 2013-06-22 |
+----+-----+----+-----------+------------+
I would like to get all values of columns A,AB, Value for the latest Date on Column A filtered on AB = I
basically the result should look like:
+----+-----+----+-----------+------------+
| Id | A | AB | Value | Date |
+----+-----+----+-----------+------------+
| 1 | abc | I | -48936.08 | 2013-06-24 |
| 3 | xyz | I | -13523.90 | 2013-06-24 |
| 7 | def | I | -13523.90 | 2013-06-22 |
+----+-----+----+-----------+------------+
I have tried to use inner join twice on the same table but failed to come up with correct result.
any help would be appreciated.
thanks :)
This will work with sqlserver 2005+
;WITH a as
(
SELECT id, A,AB, Value, Date
, row_number() over (partition by A order by Date desc) rn
FROM t1
WHERE AB = 'I'
)
SELECT id, A,AB, Value, Date
FROM a WHERE rn = 1
; WITH x AS (
SELECT id
, a
, ab
, "value"
, "date"
, Row_Number() OVER (PARTITION BY a ORDER BY "date" DESC) As row_num
FROM your_table
WHERE ab = 'I'
)
SELECT *
FROM x
WHERE row_num = 1

Resources