SQL different between sum(c1)*sum(c2) and sum(c1*c2) - sql

In SQL language what's the different results or performence between
sum(c1) * sum(c2) from t
and
sum(c1 * c2) from t
I use it to sum sales totals
select sum(price * quantity) as total from Bill
so what's the best choice?

Vertical and Horizontal summations ... assuming no NULLS
declare #mytable table (a int, b int)
insert into #mytable
values
(1,1),
(2,3)
select * from #mytable
select sum(a) * sum(b) from #mytable -- result is 12 .. vertical/column, summarize column first then multiply to other column
select sum(a*b) from #mytable --- result is 7 .. horizontal/row, summarize the product of a and b

This is not a matter of SQL. It's just basic math. Assuming c1=(0,1) and c2=(2,3). Then:
sum(c1)*sum(c2) alias... (0+1)*(2+3) = 5
is not the same as:
sum(c1*c2) alias... (0*2)+(1*3) = 3

NULLs and Zeros are one concern
Declare #YourTable table (C1 money,C2 money)
Insert Into #YourTable values
(100,10)
,(100,null)
Select sum(c1) * sum(c2) -- 2000.00
From #YourTable
Select sum(c1 * c2) -- 1000.00
From #YourTable

Related

multiply values from 2 tables sql server

I have two tables and want to multiply values together if they satisfy a condition. I looked at Multiply 2 values from 2 different tables
to no avail
I want to multiply all values in #Temp1 with the corresponding value from #Temp2 where the month from #Temp1 is the same as the month from #Temp2.
I tried
select costs * ratio as Value
from #Temp1, #Temp2
where #Temp2.ratio = cast(SUBSTRING(#Temp1.date,5,2)as int)
to no avail
I want:
costs date ratio
234.33 20170103 23.433
56.65 20170203 11.33
I am working with SQL Server2012, and any help will be appreciated.
Table #Temp1
234.33 20170103
56.65 20170203
Table #Temp2
0.1 1
0.2 2
0.3 3
IF OBJECT_ID ('tempdb..#Temp1') IS NOT NULL
DROP TABLE #Temp1
IF OBJECT_ID ('tempdb..#Temp2') IS NOT NULL
DROP TABLE #Temp2
create table #Temp1
(
costs float,
date Varchar(50)
)
create table #Temp2
(
ratio float,
month int
)
insert into #Temp1
values (234.33, 20170103)
insert into #Temp1
values (56.65, 20170203)
insert into #Temp2
values (.1,01)
insert into #Temp2
values (.2,02)
insert into #Temp2
values (.3,03)
select ratio from #Temp2 where month=3
select cast(SUBSTRING(date,5,2)as int) as month from #Temp1
select * from #Temp1
select * from #Temp2
select costs * ratio as Value
from #Temp1, #Temp2
where #Temp2.ratio = cast(SUBSTRING(#Temp1.date,5,2)as int)
If I understood correctly, it should be :
where #Temp2.month = cast(SUBSTRING(#Temp1.date,5,2)as int)
Instead :
where #Temp2.ratio = cast(SUBSTRING(#Temp1.date,5,2)as int)
I am a bonehead.
it was a typo:
select *, costs * ratio as Value
from #Temp1, #Temp2
where #Temp2.month = cast(SUBSTRING(#Temp1.date,5,2)as int)
works
Try now and give me remarks.
select month , case when #Temp2.month = cast(SUBSTRING(#Temp1.date,5,2)as int) then costs * ratio else null End as Value
from #Temp1
left join #Temp2 on
#Temp2.month = cast(SUBSTRING(#Temp1.date,5,2)as int)
It was minor typo but the panic one, used ratio instead of date in the comparison
Above change will resolve your problem but still you can follow the few other major things
1.Avoid using keywords as column names as date, month
2.You don't need to cast the value in INT because it's implicitly converted before comparison
select t1.costs,
t1.date,
(costs * ratio) as ratio
from #Temp1 t1
INNER JOIN #Temp2 t2 ON t2.month = SUBSTRING(t1.date,5,2)

SQL Server window function for running percentage

I know there are several examples of recursion with CTE and so on, but how can this be accomplished just by using window functions in SQL Server 2012:
CREATE TABLE #temp
(
ID INT PRIMARY KEY IDENTITY(1,1) NOT NULL,
Percentage INT NOT NULL
)
DECLARE #Calculated MONEY = 1000
INSERT INTO #temp ( Percentage ) VALUES ( 100 )
INSERT INTO #temp ( Percentage ) VALUES ( 90)
INSERT INTO #temp ( Percentage ) VALUES ( 60)
INSERT INTO #temp ( Percentage ) VALUES ( 50)
INSERT INTO #temp ( Percentage ) VALUES ( 100)
And the result would be a running percentage like so (we are starting with $1000)
id percentage calculated
-- -------- ---------
1 100 1000
2 50 500
3 90 450
4 80 360
5 100 360
So the value for the next row is the percentage multiplied by the calculated value above that row. Can LAG be used on a computed alias?
Thanks,
You need a running product of the percentages instead of always comparing 2 consecutive rows, which is why LEAD and LAG won't work here.
You can use a windowed sum to keep a running product of the percentages against your variable to get your desired calculation:
SELECT
ID,
Expected,
EXP(SUM(LOG(CONVERT(FLOAT, Percentage) / 100)) OVER (ORDER BY ID)) * #Calculated AS Actual
FROM #Temp
Adding this to your sample code (with a column I added for your expected output):
CREATE TABLE #temp
(
ID INT PRIMARY KEY IDENTITY(1,1) NOT NULL,
Percentage INT NOT NULL,
Expected MONEY NOT NULL
)
DECLARE #Calculated MONEY = 1000
INSERT INTO #temp ( Percentage, Expected ) VALUES ( 100 , 1000)
INSERT INTO #temp ( Percentage, Expected ) VALUES ( 50, 500)
INSERT INTO #temp ( Percentage, Expected ) VALUES ( 90, 450)
INSERT INTO #temp ( Percentage, Expected ) VALUES ( 80, 360)
INSERT INTO #temp ( Percentage, Expected ) VALUES ( 100, 360)
SELECT
ID,
Expected,
EXP(SUM(LOG(CONVERT(FLOAT, Percentage) / 100)) OVER (ORDER BY ID)) * #Calculated AS Actual
FROM #Temp
This will yield your expected output:
ID Expected Actual
----------- --------------------- ----------------------
1 1000.00 1000
2 500.00 500
3 450.00 450
4 360.00 360
5 360.00 360
you can use recursive cte to get the desired result
with cte
as
(
select id, percentage, 1000 as calculated
from #temp
where id =1
union all
select t.id, t.percentage, t.percentage*cte.calculated/100 as calculated
from #temp t
join cte
on t.id = cte.id+1
)
select * from cte
I'm afraid, widow functions won't help here (at least they won't make it simple). The easiest way to achieve your goal is update statement with double assignment:
alter table #temp add VAL decimal
declare #val decimal = 1000
update t set
#val = VAL = #val * Percentage / 100
from (select top 100 percent * from #temp order by id) as t
select * from #temp

Is there a way to return more than 1 row in select without using existing tables

Simple question, just out of curiosity.
For example select 1,2,3 that will show table with one column and three rows.
Something like this: select values(1),(2),(3)
*with one select statement
An example for my comment in your post.
DECLARE #TABLE TABLE (ONE INT, TWO INT, THREE INT)
INSERT INTO #TABLE VALUES (1,2,3)
SELECT UP.COL, UP.VALUE
FROM #TABLE
UNPIVOT (VALUE FOR COL IN (ONE,TWO,THREE)) UP
Query:
DECLARE #t TABLE (i1 INT, i2 INT, i3 INT)
INSERT INTO #t VALUES (1, 2, 3)
SELECT t.*
FROM #t
CROSS APPLY (
VALUES(i1), (i2), (i3)
) t(value)
Output:
value
-----------
1
2
3
Additional info:
http://blog.devart.com/is-unpivot-the-best-way-for-converting-columns-into-rows.html
As it appears there is a simple code that I've been searching for:
select n from (values (1),(2),(3)) D(c);

Turn value into singular row

Current
Name Quantity
---------------
Stella 2
Jennifer 2
Greg 3
Requested result
Name Quantity
---------------
Stella 1
Stella 1
Jennifer 1
Jennifer 1
Greg 1
Greg 1
Greg 1
How should I do it?
declare #T table
(
Name varchar(50),
Sales int
)
insert into #T values
('Stella', '2'),
('Jennifer', '2'),
('Greg', '3')
If the maximum value in the quantity column is known to be less than 32,767, you can use Recursion to generate numbers and join the Numbers to achieve your result.
/*******************************************
Max Recursion Count in SQL Server is 32767
Limitation of 32767 Numbers!
******************************************/
;WITH Numbers (Number) AS
(
SELECT 1
UNION ALL
SELECT 1 + Number FROM Numbers WHERE Number < 100
)
SELECT m.Name,
Quantity = 1
FROM MyTable m
JOIN #numbers n ON m.Quantity <= n.Number
OPTION (MAXRECURSION 32767);
Using recursion and borrowing Michael Fredrickson's setup code:
declare #T table (
Name varchar(50),
Sales int
)
insert into #T values ('Stella', '2')
insert into #T values ('Jennifer', '2')
insert into #T values ('Greg', '3')
-- Recursive verion
;with People (Name, Sales) as
(
select Name, Sales
from #T
union all
select Name, Sales - 1
from People
where Sales - 1 > 0
)
select Name, 1 as Quantity
from People
option (maxrecursion 0) -- Recurse without limit
This seems to run faster on my box (5x faster than Michael Fredrickson's according to query plan, but with many more logical reads), not that it matters much.
You'll probably want to have a pre-populated numbers table to do this:
declare #T table (
Name varchar(50),
Sales int
)
declare #numbers table (
Number int
)
insert into #numbers values (1)
insert into #numbers values (2)
insert into #numbers values (3)
insert into #numbers values (4)
-- Etc... up to however many numbers is the max possible value for sales...
insert into #T values ('Stella', '2')
insert into #T values ('Jennifer', '2')
insert into #T values ('Greg', '3')
SELECT
t.Name,
1 AS Sales
FROM
#T t JOIN
#numbers n ON
t.Sales >= n.Number
ORDER BY t.Name
That's how you could do it, but I'm not sure on why you would want to do it.

transact-sql question

Assume there were 100 records in tableA and tableA contained a column named 'price'.
How do I select the first-n record if where sum of price > a certain amount (e.g. 1000) without using cursor?
thanks
Top N implies some kind of order, which you did not supply, so I assumed any random order.
You can change this on the OVER clause of the ROW_NUMBER().
Try something like
DECLARE #Table TABLE(
Price FLOAT
)
INSERT INTO #Table SELECT 1
INSERT INTO #Table SELECT 11
INSERT INTO #Table SELECT 12
INSERT INTO #Table SELECT 15
INSERT INTO #Table SELECT 10
INSERT INTO #Table SELECT 65
INSERT INTO #Table SELECT 100
DECLARE #TotalPrice FLOAT
SELECT #TotalPrice = 100
;WITH Vals AS (
SELECT *,
ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) RNR
FROM #Table
)
, Totals AS (
SELECT v.RNR,
SUM(vP.Price) TotalPrice
FROM Vals v LEFT JOIN
Vals vP ON v.RNR >= vP.RNR
GROUP BY v.RNR
)
, LimitValue AS (
SELECT TOP 1
RNR
FROM Totals
WHERE TotalPrice >= #TotalPrice
ORDER BY RNR
)
SELECT *
FROM Vals
WHERE RNR <= (
SELECT RNR
FROM LimitValue
)
select price from tableA
where price > 1000
limit n;
n - no. of records you want in result set
--
Cheers