Finding common value in two columns - sql-server

I have a problem with a query where i need to get all the common values in column #2 that are for every element of column #1.
For example:
Column #1 Column #2
-------------------
21 2.00
21 5.00
21 6.00
21 8.00
21 9.00
41 2.00
41 3.00
41 4.00
41 5.00
41 6.00
41 9.00
52 2.00
52 5.00
52 9.00
52 10.00
52 20.00
Result
-------------------
2.00
5.00
Any help will be greatly appreciated.
Juan Alvarez

SELECT column2
FROM YourTable
GROUP BY column2
HAVING COUNT(*) = (SELECT COUNT(DISTINCT column1) FROM YourTable)

Related

How to update multiple rows in SQL Server?

Here is the Insert into select query which selects multiple rows from GradePackages table and inserts the data into EmployeePackages table:
insert into EmployeePackages (EmployeeId, GradeId, PackageId, Amount)
select
#EmployeeId,
#GradeId,
PackageId,
Amount
from
GradePackages
where
GradeId = #GradeId
Here #EmployeeId and GradeId have a single value each. But PackageId and Amount, each of them have 5 values.
The Insert query works fine, but the problem is with the update query. I need to update i.e. copy rows from the GradePackages table (where I input a specific GradeId) into the EmployeePackages table (where specific EmployeeId is input). I know it will work on a single row but there are multiple rows and that is the problem. I have tried different types of Update queries but it doesn't work. Have a look please. Thank you.
EmployeePackages table:
Id
EmployeeId
GradeId
PackageId
Amount
13
1036
30
1
29980.00
14
1036
30
2
5000.00
15
1036
30
3
0.00
16
1036
30
4
0.00
17
1036
30
5
0.00
18
1037
31
1
34000.00
19
1037
31
2
6000.00
20
1037
31
3
0.00
21
1037
31
4
0.00
22
1037
31
5
0.00
GradePackages table:
Id
GradeId
PackageId
Amount
11
30
1
34650.00
12
30
2
5000.00
13
30
3
0.00
14
30
4
0.00
15
30
5
0.00
16
29
1
41090.00
17
29
2
6000.00
18
29
3
0.00
19
29
4
0.00
20
29
5
0.00
Output needed (EmployeePackages):
Id
EmployeeId
GradeId
PackageId
Amount
13
1036
29
1
41090.00
14
1036
29
2
6000.00
15
1036
29
3
0.00
16
1036
29
4
0.00
17
1036
29
5
0.00
18
1037
31
1
34000.00
19
1037
31
2
6000.00
20
1037
31
3
0.00
21
1037
31
4
0.00
22
1037
31
5
0.00
Expected results:
Let's say I select rows with GradeId = 29 (5 rows) from GradePackages and update EmployeePackages where EmployeeId = 1036
I believe you said Update; not insert so...
DECLARE #GradeID AS Numeric(4,0)=29
DECLARE #EmployeeID as Numeric(4,0)=1036
UPDATE EmployeePackages
SET EmployeePackages.Amount = GP.Amount,
EmployeePackages.GradeID = #GradeID --added this and , above.
FROM EmployeePackages EP
INNER JOIN GradePackages GP
ON EP.PackageID = GP.PackageID
WHERE EP.EmployeeID = #EmployeeID
AND GP.GradeID = #GradeID
Consider:
Parameterizing SQL UPDATE query
SQL Update from One Table to Another Based on a ID Match
Example Fiddle: Special thanks to RF1991 so I didn't have to re-create the fiddle.
Resulting in:
+---------+------------+---------+-----------+----------+
| Id | EmployeeId | GradeId | PackageId | Amount |
+---------+------------+---------+-----------+----------+
| 13 | 1036 | 29 | 1 | 41090.00 |
| 14 | 1036 | 29 | 2 | 6000.00 |
| 15 | 1036 | 29 | 3 | 0.00 |
| 16 | 1036 | 29 | 4 | 0.00 |
| 17 | 1036 | 29 | 5 | 0.00 |
| 18 | 1037 | 31 | 1 | 34000.00 |
| 19 | 1037 | 31 | 2 | 6000.00 |
| 20 | 1037 | 31 | 3 | 0.00 |
| 21 | 1037 | 31 | 4 | 0.00 |
| 22 | 1037 | 31 | 5 | 0.00 |
+---------+------------+---------+-----------+----------+
for update using Subquery
UPDATE employeepackages
SET employeepackages.gradeid = t.gradeid,
employeepackages.amount = t.amount
FROM (SELECT GP.gradeid,
GP.packageid,
GP.amount
FROM gradepackages GP
FULL JOIN employeepackages EP
ON EP.gradeid = GP.gradeid
AND EP.packageid = GP.packageid
WHERE EP.gradeid IS NULL) t
WHERE employeeid = #EmployeeId
AND employeepackages.gradeid = #GradeId
AND employeepackages.packageid = t.packageid
subquery fiddle
or with CTE
;with t as(
SELECT
GP.gradeid ,
GP.packageid ,
GP.amount
FROM gradepackages GP
FULL JOIN employeepackages EP
ON EP.gradeid = GP.gradeid
AND EP.packageid = GP.packageid
WHERE EP.gradeid IS NULL )
UPDATE e
SET e.gradeid = t.gradeid,
e.amount = t.amount
FROM employeepackages e
JOIN t
ON e.packageid = t.packageid
WHERE e.employeeid = #EmployeeId
AND e.GradeId = #GradeId
cte fiddle

Subtract depletion And Limit for SUM

First I'm using AdventureWork2019 as a reference
I have a query where I'm joining 5 Tables
USE [AdventureWorks2019]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Alter PROCEDURE dbo.TestLocation
#UseDate DateTime
AS
BEGIN
SET NOCOUNT ON;
SELECT prodID
,SUM(PurchQty) AS TotalPurchase
,SUM(SalesQty) AS TotalSell
,StartDate
from (
SELECT DISTINCT WO.ProductID AS prodID
, StartDate
,WO.OrderQty AS PurchQty
,SOD.OrderQty AS SalesQty
FROM Sales.SalesOrderDetail SOD
LEFT JOIN Production.WorkOrderRouting WOR ON WOR.ProductID = SOD.ProductID
--LEFT JOIN Production.Location PL ON PL.LocationID = WOR.LocationID
--The above Join is the one for the locationID and it's working Fine
LEFT JOIN Production.WorkOrder WO ON WO.ProductID = SOD.ProductID
FULL OUTER JOIN Purchasing.PurchaseOrderDetail POD ON POD.ProductID = SOD.ProductID
WHERE StartDate = #UseDate
-- AND PL.LocationID >= 10
) Test3
Group by prodID,StartDate
order by prodID ASC, StartDate
END
GO
EXEC TestLocation '2011-07-02 00:00:00.000'
Output(sample):
prodID TotalPurc TotalSell StartDate
717 8 36 2011-07-02 00:00:00.000
730 9 47 2011-07-02 00:00:00.000
744 2 3 2011-07-02 00:00:00.000
747 12 21 2011-07-02 00:00:00.000
749 5 15 2011-07-02 00:00:00.000
761 16 138 2011-07-02 00:00:00.000
775 26 91 2011-07-02 00:00:00.000
777 12 78 2011-07-02 00:00:00.000
802 6 21 2011-07-02 00:00:00.000
804 40 60 2011-07-02 00:00:00.000
806 16 138 2011-07-02 00:00:00.000
807 24 23 2011-07-02 00:00:00.000
810 21 28 2011-07-02 00:00:00.000
811 6 21 2011-07-02 00:00:00.000
813 8 37 2011-07-02 00:00:00.000
817 21 28 2011-07-02 00:00:00.000
And another Table For LocationID (as a warehouse)
SELECT LocationID,CostRate,Availability
FROM Production.Location
WHERE LocationID >= 10
order by CostRate ASC
LocationID CostRate Availability
50 12.25 120.00
60 12.25 120.00
30 14.50 120.00
40 15.75 120.00
45 18.00 80.00
10 22.50 96.00
20 25.00 108.00
What I want to do is to take each LoactionId and ProdID and take TotalPurc to the location and decrement the quantity in the Availability column, each TotalSell will increment the Availability column. The max Availability quantity is 130.
If all locations have no Available quantity that is the Available is 0 for all locations then it will stop.
the above will work with the date specified as you can check the query and run it if you have
AdventureWork2019
simple output to check how I want the data to be:
prodID TotalPurc TotalSell StartDate
717 8 36 2011-07-02 00:00:00.000
730 9 47 2011-07-02 00:00:00.000
744 2 3 2011-07-02 00:00:00.000
747 12 21 2011-07-02 00:00:00.000
749 5 15 2011-07-02 00:00:00.000
LocationID CostRate Availability
50 12.25 120.00
60 12.25 120.00
30 14.50 120.00
40 15.75 120.00
45 18.00 80.00
10 22.50 96.00
20 25.00 108.00
Output :
prodID TotalPurc TotalSell StartDate LocationID Availability Remaining
717 8 36 2011-07-02 00:00:00.000 50 130 18
717 8 36 2011-07-02 00:00:00.000 60 130 8
717 8 36 2011-07-02 00:00:00.000 30 128 0
--what happened above is that I took the (120-8) = 112 then 112+36 = 148 we only can use 130 then the remaining is 18 then we took the next `LocationID` with the least Cost (120+18 = 138 we can use 130 so we took the 8) and used it in the next `LocationID`
730 9 47 2011-07-02 00:00:00.000 30 130 36
730 9 47 2011-07-02 00:00:00.000 40 130 26
730 9 47 2011-07-02 00:00:00.000 45 106 0
744 2 3 2011-07-02 00:00:00.000 45 107 0
747 12 21 2011-07-02 00:00:00.000 45 116 0
749 5 15 2011-07-02 00:00:00.000 45 126 0
--the above is the same as the first 3 rows we subtract and add to the availability
The other condition is that if all locations reached 0 or 130 then stop
How can I do that in SQL Server? I tried using CTE but didn't work well with me and tried the cursor which I think is the best for this kind of thing but didn't achieve anything.
Thank you in advance
Edit :
ALTER FUNCTION GetStockMovment
(
-- Add the parameters for the function here
#ForDate Datetime
)
RETURNS #Sums TABLE (
RemoveQTY Numeric(24, 7),
ADDQTY Numeric(24, 7)
)
AS
BEGIN
Declare #WoSum Numeric(24, 7),
#SODSUM Numeric(24, 7),
#WORSum Numeric(24, 7),
#PODSum Numeric(24, 7)
select #SODSUM = SUM(SOD.OrderQty) from Sales.SalesOrderDetail SOD
INNER JOIN Sales.SalesOrderHeader SOH ON SOD.SalesOrderID = SOH.SalesOrderID
where SOH.OrderDate = #ForDate
select #WoSum = sum(orderQty) from Production.WorkOrder
where StartDate = #ForDate
select #PODSum = sum(POD.OrderQty) from Purchasing.PurchaseOrderDetail POD
INNER JOIN Purchasing.PurchaseOrderHeader POH ON POD.PurchaseOrderID = POH.PurchaseOrderID
where POH.OrderDate = #ForDate
select #WoSum = sum(WO.OrderQty) from Production.WorkOrder WO
where WO.DueDate = #ForDate
INSERT INTO #Sums (RemoveQTY,ADDQTY)
SELECT isnull(#SODSUM,0) + isnull(#WORSum,0) , isnull(#PODSum,0) + isnull(#WoSum,0)
RETURN;
END;
GO
select * from dbo.GetStockMovment ('2014-05-26 00:00:00.000')
Output:
RemoveQTY ADDQTY
189.0000000 5334.0000000
You should use LAG or LEAD function.
https://learn.microsoft.com/en-us/sql/t-sql/functions/lead-transact-sql?view=sql-server-ver15
https://learn.microsoft.com/en-us/sql/t-sql/functions/lag-transact-sql?view=sql-server-ver15

How to add values in sql

Hey i have a table like this
Product_name Rate Cost GST_percentage Recipt_no Amount Final_Amount ID Description GST_price Quantity OrderID Discount Net_Unit_Price Stock_Pending Payment_Pending
SINGTEL DATA + EZ $10 1.5 GB 7 DAYS 10 120.00 5 1 120.00 126 1 A 6.00 12 ODR1 0.00 10.00 Received Paid
SINGTEL DATA + EZ $10 1.5 GB 7 DAYS 12 180.00 0 2 180.00 180.00 2 A 0.00 15 ODR2 0.00 12.00 NULL NULL
SINGTEL DATA + EZ $8 CHINA 888 10 120.00 0 2 120.00 120.00 3 B 0.00 12 ODR2 0.00 10.00 NULL NULL
and i want to show the final_Amount column value groupped by order Id.then i want to show the final_amount for those which is Payment_Pending status is not null but i can't get the correct result.
Note:
i got a result as
query:
SELECT [OrderID],
SUM(convert(float,[Final_Amount])) as Final_Amount,
(select sum(convert(float,Final_Amount)) as Final_Amount
from Purchase_Order
where Payment_Pending is not null) as paid
FROM [Purchase_Order]
group by [OrderID]
order by OrderID desc
OrderID Final_Amount paid
ODR2 300 126
ODR1 126 126
but i want like this
OrderID Final_Amount paid
ODR2 300 0
ODR1 126 126
(Because ODR2 Payment_Pending Column filled with null)
Probably your sub-query is wrong. It need to include a reference to OrderId of main query
SELECT [OrderID],
SUM(convert(float,[Final_Amount])) as Final_Amount,
(select sum(convert(float,Final_Amount)) as Final_Amount
from Purchase_Order x
where x.Payment_Pending is not null
and x.OrderId = p.OrderId) as paid
FROM [Purchase_Order] p
group by [OrderID]
order by OrderID desc

Pivot the data in SQL Server

I have the following table data
ID Night_111 NightOT_112 NightLeave_113
----------------------------------------------------
1 8.00 0.00 0.00
2 16.00 4.00 0.00
3 8.00 0.00 2.00
I want that table to convert it into this structure:
ID wageType hours
---------------------------
1 111 8
2 111 16
2 112 4
3 111 8
3 113 2
Please help
Thanks
There are several ways, but I advocate using apply:
select v.*
from t cross apply
(values (id, 111, Night_111), (id, 112, NightOT_112), (id, 113, NightOT_112)
) v(ID, wageType, hours)
where v.hours > 0;
You can do something similar using union all or unpivot. However, apply implements something called a lateral join, which is a very powerful operator and useful many other situations.

Average value depending on cumulative value from other column aka running total

I've sifted through the various sql-server tagged threads using AVERAGE and Cumulative as search terms. Various desperate answers, but I can't cobble them together for my needs. The use case is to find the initial average value (cumulative value/cumulative days on) for a time period when cumulative days on is greater than 60 and less than 90.
Below is a table where ID identifies the object, VALUE is the amount reported on a monthly basis and DAYSON is the number of days in that month where the object ran to produce the value. YEARMONTH is date value on which on can sort.
ID VALUE DASYON YEARMONTH
1 166 27 201502
1 1 2 201505
1 569 19 201507
1 312 19 201508
2 364 27 201502
2 328 31 201503
2 242 29 201504
2 273 31 201505
2 174 30 201506
2 188 25 201507
2 203 25 201508
3 474 28 201502
3 521 31 201503
3 465 30 201504
3 473 31 201505
3 434 30 201506
3 404 31 201507
I would like to create a summary table that averages the cumulative value divided by the cumulative days uniquely for each ID where cumulative days is greater than 60 and less than 90. Below is a table that with the cumulative values. (I generated this in Excel)
ID VALUE cumValue DASYON cumDaysOn YEARMONTH
1 166 166 27 27 201502
1 1 167 2 29 201505
1 569 736 19 48 201507
1 312 1048 19 67 201508
2 364 364 27 27 201502
2 328 692 31 58 201503
2 242 934 29 87 201504
2 273 1207 31 118 201505
2 174 1381 30 148 201506
2 188 1569 25 173 201507
2 203 1772 25 198 201508
3 474 474 28 28 201502
3 521 505 31 59 201503
3 465 535 30 89 201504
3 473 566 31 120 201505
3 434 596 30 150 201506
3 404 627 31 181 201507
I try this based on other threads:
SELECT
ID,
Value,
SUM(Value) OVER (ORDER BY ID, YearMonth) [cumValue],
DaysOn,
SUM (DaysOn) OVER (Order by ID, YearMonth) as cumDaysOn,
YearMonth
FROM table
WHERE DAYSON > 0 and Liquid > 0 and YearMonth > 201501
GROUP BY ID, YearMonth, Value, DaysOn
ORDER BY ID, yearmonth
I can't get it to iterate over the ID; it just keeps summing down the column. If I could create a table or view like the one above, then I could always use a select statement and divide cumvalue by cumdayson.
Below is a table to show where I would get the initial average value (InititalAverageValue) based on the criteria:
ID VALUE cumValue DASYON cumDaysOn YEARMONTH InitalAvgValue
1 166 166 27 27 201502
1 1 167 2 29 201505
1 569 736 19 48 201507
1 312 1048 19 67 201508 55
2 364 364 27 27 201502
2 328 692 31 58 201503
2 242 934 29 87 201504 32
2 273 1207 31 118 201505
2 174 1381 30 148 201506
2 188 1569 25 173 201507
2 203 1772 25 198 201508
3 474 474 28 28 201502
3 521 505 31 59 201503
3 465 535 30 89 201504 18
3 473 566 31 120 201505
3 434 596 30 150 201506
3 404 627 31 181 201507
Ultimately what I desire is table as such:
ID InitalAvgValue
1 55
2 32
3 18
Thanks in advance for any help.
The crux is that you need a running total. There are several approaches to calculating running totals, but they have various tradeoffs between simplicity and performance. The "best" approach depends on the expected size of your data set and whether you are using SQL Server 2012 or an earlier version. The following article describes some different options along with the pros and cons:
http://sqlperformance.com/2012/07/t-sql-queries/running-totals
Here's a quick example using correlated subqueries, which may be reasonable for small data sets, but likely would not scale well to larger data:
SELECT
ID,
ROUND(AVG(CAST(CumulativeValue AS FLOAT) / CAST(CumulativeDaysOn AS FLOAT)), 1) AS Average
FROM
(
SELECT
ID,
Value,
DaysOn,
(SELECT SUM(Value) FROM ExampleTable t2 WHERE t1.ID = t2.ID and t2.YearMonth <= t1.YearMonth) AS CumulativeValue,
(SELECT SUM(DaysOn) FROM ExampleTable t2 WHERE t1.ID = t2.ID and t2.YearMonth <= t1.YearMonth) AS CumulativeDaysOn
FROM
ExampleTable t1
) AS ExampleWithTotals
WHERE
CumulativeDaysOn > 60 AND CumulativeDaysOn < 90
GROUP BY
ID
ORDER BY
ID
;
Output:
ID Average
1 15.6
2 10.7
3 16.4

Resources