Sum of coloumn based on two condition in where cluase - sql-server

I have table structure
ACNo Deal PRODTYPE INT AMT
100 123 OS 23
100 123 EX 7
I have to group by Deal,AC NO and have to report other column as well, but for Int amount have to do sum of for both prod type.
How I can implement it?
Result
AC No Deal Total INT
100 123 30

Try this
SELECT AccNo, DEAL, SUM([INT AMT]) AS Total Amount
FROM Table
GROUP BY AccNo, DEAL

something like this ?
select ACNo,
Deal,
sum([INT AMT]) as [Total INT]
from unknowntablename
group by ACNo, Deal
You can test this like this :
declare #table table (ACNo int, Deal int, PRODTYPE varchar(2), [INT AMT] int)
insert into #table values (100, 123, 'OS', 23)
insert into #table values (100, 123, 'EX', 7)
select ACNo,
Deal,
sum([INT AMT]) as [Total INT]
from #table
group by ACNo, Deal
the outcome will be :
ACNo Deal Total INT
100 123 30

Related

Conditionally move values between columns

I have the following record set output:
ID Name Pay_Type Paid_Amnt Interest_Amnt
1 John Smith Benefit 1075 0
1 John Smith Interest 1.23 0
2 Tom Ryder Benefit 1123 0
3 Mark Thompson Benefit 1211 0
3 Mark Thompson Interest 1.34 0
What I'd like is for values with the Pay_Type = Interest to be placed in the Interest column.
Desired output:
ID Name Pay_Type Pay_Type 2 Paid_Amnt Interest_Amnt
1 John Smith Benefit Interest 1075 1.23
2 Tom Ryder Benefit NULL 1123 0
3 Mark Thompson Benefit Interest 1211 1.34
I tried something like the following:
Select row_number()over(partition by id, case when pay_type = 'Interest' then interest_amnt = paid_amnt
when pay_type = 'Interest' then paid_amnt = 0 end) as new_interest
Does anyone know how to get the desired results?
Thank you
declare #t table(id int, pay_type varchar(25), name varchar(100), paid_amnt float, interest_amnt float)
insert into #t values(1, 'Benefit', 'John Smith', 1075, 0),
(1, 'Interest', 'John Smith',1.23, 0),
(2, 'Benefit', 'Tom Ryder', 1123, 0),
(3, 'Benefit', 'Mark Thompson', 1211, 0),
(4, 'Interest', 'Mark Thompson', 1.34, 0)
select * from #t
Just in case you can have more than 2 records per person, I believe this will give you what you want, it utilizes a couple of subqueries and group by,
subquery x groups your records so you get the interest sums and benefits sums in a row per user,
subquery y uses CASE expressions to place the summed amounts into their proper columns or zero in case of it being Benefit/Interest and adds the pay type columns of pay_type1 and pay_type2 with values of Benefit and Interest respectively,
outer query groups everything together into 1 row per user, and sums their interest and benefit columns respectively:
SELECT y.[id] AS [ID], y.[name] AS [Name],
y.[pay_type1] AS [Pay_Type], y.[Pay_Type2], SUM(y.[Paid_Amnt]) AS [Paid_Amnt],
SUM(y.[Interest_Amnt]) AS [Interest_Amnt]
FROM
(
SELECT id, name, 'Benefit' AS [pay_type1], 'Interest' AS [pay_type2],
CASE WHEN pay_type = 'Benefit' THEN x.Amount ELSE 0 END AS [Paid_Amnt],
CASE WHEN pay_type = 'Interest' THEN x.Amount ELSE 0 END AS [Interest_Amnt]
FROM
(
SELECT id, pay_type, name, SUM(paid_amnt) AS [Amount]
FROM table as t
GROUP BY id, pay_type, name
) AS x
) AS y
GROUP BY y.[id], y.[name], y.[pay_type1], y.[pay_type2]

In T-SQL is there a built-in command to determine if a number is in a range from another table

This is not a homework question.
I'm trying to take the count of t-shirts in an order and see which price range the shirts fall into, depending on how many have been ordered.
My initial thought (I am brand new at this) was to ask another table if count > 1st price range's maximum, and if so, keep looking until it's not.
printing_range_max printing_price_by_range
15 4
24 3
33 2
So for example here, if the order count is 30 shirts they would be $2 each.
When I'm looking into how to do that, it looks like most people are using BETWEEN or IF and hard-coding the ranges instead of looking in another table. I imagine in a business setting it's best to be able to leave the range in its own table so it can be changed more easily. Is there a good/built-in way to do this or should I just write it in with a BETWEEN command or IF statements?
EDIT:
SQL Server 2014
Let's say we have this table:
DECLARE #priceRanges TABLE(printing_range_max tinyint, printing_price_by_range tinyint);
INSERT #priceRanges VALUES (15, 4), (24, 3), (33, 2);
You can create a table with ranges that represent the correct price. Below is how you would do this in pre-2012 and post-2012 systems:
DECLARE #priceRanges TABLE(printing_range_max tinyint, printing_price_by_range tinyint);
INSERT #priceRanges VALUES (15, 4), (24, 3), (33, 2);
-- post-2012 using LAG
WITH pricerange AS
(
SELECT
printing_range_min = LAG(printing_range_max, 1, 0) OVER (ORDER BY printing_range_max),
printing_range_max,
printing_price_by_range
FROM #priceRanges
)
SELECT * FROM pricerange;
-- pre-2012 using ROW_NUMBER and a self-join
WITH prices AS
(
SELECT
rn = ROW_NUMBER() OVER (ORDER BY printing_range_max),
printing_range_max,
printing_price_by_range
FROM #priceRanges
),
pricerange As
(
SELECT
printing_range_min = ISNULL(p2.printing_range_max, 0),
printing_range_max = p1.printing_range_max,
p1.printing_price_by_range
FROM prices p1
LEFT JOIN prices p2 ON p1.rn = p2.rn+1
)
SELECT * FROM pricerange;
Both queries return:
printing_range_min printing_range_max printing_price_by_range
------------------ ------------------ -----------------------
0 15 4
15 24 3
24 33 2
Now that you have that you can use BETWEEN for your join. Here's the full solution:
-- Sample data
DECLARE #priceRanges TABLE
(
printing_range_max tinyint,
printing_price_by_range tinyint
-- if you're on 2014+
,INDEX ix_xxx NONCLUSTERED(printing_range_max, printing_price_by_range)
-- note: second column should be an INCLUDE but not supported in table variables
);
DECLARE #orders TABLE
(
orderid int identity,
ordercount int
-- if you're on 2014+
,INDEX ix_xxy NONCLUSTERED(orderid, ordercount)
-- note: second column should be an INCLUDE but not supported in table variables
);
INSERT #priceRanges VALUES (15, 4), (24, 3), (33, 2);
INSERT #orders(ordercount) VALUES (10), (20), (25), (30);
-- Solution:
WITH pricerange AS
(
SELECT
printing_range_min = LAG(printing_range_max, 1, 0) OVER (ORDER BY printing_range_max),
printing_range_max,
printing_price_by_range
FROM #priceRanges
)
SELECT
o.orderid,
o.ordercount,
--p.printing_range_min,
--p.printing_range_max
p.printing_price_by_range
FROM pricerange p
JOIN #orders o ON o.ordercount BETWEEN printing_range_min AND printing_range_max
Results:
orderid ordercount printing_price_by_range
----------- ----------- -----------------------
1 10 4
2 20 3
3 25 2
4 30 2
Now that we have that we can

Accessing prior rows and divide its value by current row

I have the rows below, and i want to access prior row and divide its value by current row. For every row, i need to calculate the Vi value, this Vi value is equal to Vi-1/Vi which means that:
Given the table
Table T
id value out
1 100
2 200
3 10
4 50
I want to generate these values
V1 = 100
V2= 100/200 = 0.5
V3 = 0.5/10 = 0.05
V4 = 0.05/50 = 0.001
So at the end i want the following output:
id value out
1 100 100
2 200 0.5
3 10 0.05
4 50 0.001
I tried using the aggregate function SUM with OVER(), but i do not know how to solve this problem as i need to divide and not sum the value
SELECT id, value, SUM(value) OVER(ORDER BY id ROWS BETWEEN
1 PRECEDING AND 1 PRECEDING ) / value as out
FROM T
Sample data:
CREATE TABLE t(
id INT,
value INT
);
INSERT INTO t VALUES
(1, 100), (2, 200), (3, 10), (4, 50);
Unfortunately, SQL do not have Product, but it should be simple to use cte. The performance should be not bad if id was indexed
DECLARE #T table (id int identity(1,1) primary key, value int)
INSERT #T VALUES (100), (200), (10), (50)
;WITH cte AS
(
SELECT id, value, CAST(value AS decimal(20,4)) AS out FROM #T WHERE id = 1
UNION ALL SELECT T.id, T.value, CAST(cte.out / T.value AS decimal(20,4)) FROM cte INNER JOIN #T T ON cte.id = T.id - 1
)
SELECT * FROM cte

SQL weighted revenue query

6I have 3 tables. Examples below.
Weight
Channel WeightFirst WeightMiddle WeightLast
Dir 40 45 50
NatS 0 0 0
PC 20 25 30
UnRef 40 45 50
Sales
saleID revenue
32150 1600.00
32153 516.00
Visits
visitID saleID visitDate channel visitRevenue
4479433 32153 2014-12-09 15:00:41.000 NatS NULL
4479434 32153 2014-12-09 14:55:21.000 PC NULL
4479435 32153 2014-12-09 15:09:01.000 UnRef NULL
4755575 32150 2014-12-07 16:41:24.000 NatS NULL
4756323 32150 2014-12-07 16:52:56.000 PC NULL
4756324 32150 2014-12-06 20:49:41.000 Dir NULL
I need to calculate visitRevenus in the Visits table based on the WeightFirst, WeightMiddle, WeightLast in the Weight table.
First visitDate in the Visits table gets WeightFirst, last visitDate gets WeightLast, and everything in between those dates gets WeightMiddle.
For example saleID 32153 has the first visitDate as visitID 4479434, so PC gets a WeightFirst of 20, then visitID 4479433 gets 0 for NatS, and visitID 4479435 gets 50 for UnRef. Total weight is 70. With saleID revenue in Sales being 516.00
I need to divide 516.00 by 70, then multiply the result by each weight and update visitRevenue in the Visits table with that result.
So PC would get 147.4285714285714 and UnRef would get 368.5714285714286. Add them together and it's 516.
The table I have hold more than just 2 saleIDs, many channels, and large amounts of visitDates. I need some SQL to update visitRevenue
with these calculated figures but am having trouble getting started. Any help would be most welcome! And if anymore info is required please ask.
Thanks
This, I think, does the trick. I don't know your system so I did not know if you could alter the underlying tables so this does everything with table variables.
BTW, it really helps to have the tables set up first :)
DECLARE #weight TABLE (
Channel varchar(max),
WeightFirst int,
WeightMiddle int,
WeightLast int)
INSERT INTO #weight VALUES
('Dir', 40,45,50),
('NatS', 0, 0, 0),
('PC', 20,25,30),
('UnRef',40,45,50)
DECLARE #sales TABLE (
salesID int,
revenue float)
INSERT INTO #sales VALUES
(32150,1600.00),
(32153,516.00)
DECLARE #visits TABLE (
visitID int,
salesID int,
visitDate datetime,
channel varchar(max),
VisitRevenue float)
INSERT INTO #visits VALUES
(4479433, 32153, '2014-12-09 15:00:41.000','NatS', NULL),
(4479434, 32153, '2014-12-09 14:55:21.000','PC', NULL),
(4479435, 32153, '2014-12-09 15:09:01.000','UnRef',NULL),
(4755575, 32150, '2014-12-07 16:41:24.000','NatS', NULL),
(4756323, 32150, '2014-12-07 16:52:56.000','PC', NULL),
(4756324, 32150, '2014-12-06 20:49:41.000','Dir', NULL)
DECLARE #visitWeight TABLE (
visitID int,
salesID int,
visitDate datetime,
channel varchar(max),
VisitRevenue float,
visitNumber int,
visitWeight int,
totalWeight float,
revenue float)
INSERT INTO #visitWeight
SELECT visitID, v.salesID, visitDate,channel,visitRevenue,
ROW_NUMBER() OVER (PARTITION BY v.salesID ORDER BY visitDate ASC) AS visitNumber ,NULL,NULL, revenue
FROM #visits v JOIN #sales s ON v.salesID=s.salesID
UPDATE #visitWeight -- this sets the first weight, also sets everything else to middle
SET visitWEIGHT =
CASE WHEN visitNumber=1 THEN WeightFirst ELSE weightMiddle END
FROM #visitWeight vw JOIN #weight w on vw.channel=w.channel
UPDATE #visitWeight -- this sets the last weight
SET visitWEIGHT = WeightLast
FROM
(SELECT salesID, max(visitNumber) AS maxVisit FROM #visitWeight GROUP BY salesID) AS t
JOIN #visitWeight vw ON t.maxVisit=vw.visitNumber JOIN
#weight w on vw.channel=w.channel
UPDATE #visitWeight
SET totalWeight = s.sumWeight,
VisitRevenue = revenue/s.sumWeight*visitWeight
FROM (SELECT salesID, SUM(visitWeight) AS sumWeight FROM #visitWeight GROUP BY salesID) AS s
SELECT * FROM #visitWeight order by salesID, visitDate

SQL-SERVER Get Result from table where Value like 1-9

I have a table WHERE there's a column that has QTY Ranges like 1-5, 6-9 etc and prices in another column. i.e
Price QTY
------------------------
Price Qty Range
----- ----------
45 1-5
35 6-9
30 10-18
Now I want to get the result from the table where Qty is 7 Therefore Price returned should be 35 ( since Qty 7 falls in range 6-9
Any help greatly appriciated
Try this :-
Declare #val int
Set #val=7
;with cte(price,startVal,endVal) as
( Select price,
parsename(replace([Qty Range],'-','.'),2),
parsename(replace([Qty Range],'-','.'),1)
from yourTable
)
Select Price from cte
where #val between startVal and endVal
Result : 35
Demo in SQL FIDDLE
If you can't redesign the table to be sane, you can use a couple of CTEs to reconstruct it as a sane table for this query:
declare #PriceRanges table (Price int,QtyRange varchar(20))
insert into #PriceRanges (Price,QtyRange) values
(45,'1-5'),
(35,'6-9'),
(30,'10-18')
declare #Search int
set #Search = 7
;with FoundDashes as (
select Price,QtyRange,CHARINDEX('-',QtyRange) as DashPos
from #PriceRanges
)
, SaneRanges as (
select Price,CONVERT(int,SUBSTRING(QtyRange,1,DashPos-1)) as LowRange,CONVERT(int,SUBSTRING(QtyRange,DashPos+1,8000)) as HighRange
from FoundDashes
)
select Price from SaneRanges where #Search between LowRange and HighRange
Produces 35 as a result.

Resources