SQL: Creating temporary variables - sql

I'm new to SQL so please consider this noob question. Also, its so embarrassing to admit that I cannot search for the right keyword in Google and I'm running out of time so I decided to ask it here.
Code:
select
*,
price * quantity as [Total price],
case
when [Total price]>100 and [Total price]<= 200 then '2%'
when [Total price]>200 and [Total price]<= 300 then '3%'
when [Total price]>300 and [Total price]<= 400 then '4%'
else '0%'
end as tax
from
grocery
As you can see, what I am trying to do is try to create a temporary variable on execution of SQL statement but, this one gives me error
Error 1: could not prepare statement [1 no such column: Total price]
How could I do this ?

A quick way would be to use a CTE (Common Table Expression). This allows you to pre-calculate some values and then refer the values in the body of the query.
If a statement with a CTE isn't the first thing in a batch, you need to end the preceding stuff with a ;:
;
With Totals as
(
select *,
price * quantity as [Total price],
from grocery
)
select *
, case
when [Total price]>100 and [Total price]<= 200 then '2%'
when [Total price]>200 and [Total price]<= 300 then '3%'
when [Total price]>300 and [Total price]<= 400 then '4%'
else '0%'
end as tax
from
Totals
The root of your problem, by the way, is that you can't define an expression and then use the expression by name in a query. You can re-use the expression, but not by name:
select x + 1 as Expr1
, (x + 1) * 2 as Expr2
from Table1
That will work, but the following won't work:
select x + 1 as Expr1
, Expr1 * 2 as Expr2 -- This won't work
from Table1

SELECT *,
case
when [Total price]>100 and [Total price]<= 200 then '2%'
when [Total price]>200 and [Total price]<= 300 then '3%'
when [Total price]>300 and [Total price]<= 400 then '4%'
else '0%'
end as tax
FROM (SELECT *, price * quantity as [Total price]
FROM grocery) A
OR
select
*,
price * quantity as [Total price],
case
when price * quantity >100 and price * quantity<= 200 then '2%'
when price * quantity>200 and price * quantity<= 300 then '3%'
when price * quantity>300 and price * quantity<= 400 then '4%'
else '0%'
end as tax
from
grocery

Related

Calculate AVG in SQL Select statement when some values are NULL

I have struggled to find a solution to this problem, so any help would be hugely appreciated.
I have two tables, lets call one table_a and one table_b, representing two possible sources of customer orders. They both contain a field called "customer_number" which I am using to outer join table_b to table_a. I am then calculating an average customer order size given the two tables.
Where i struggle is where a customer has an entry in either table, but not in both. Then my average calc returns NULL.
Table_a:
Customer Number
Total Online Orders
123456789
1350
987654321
650
Table_b:
Customer Number
Total InStore Orders
123456789
350
So basically the second customer does not have an entry in table_b.
My code as follows:
select distinct
a.[customer number],
a.[Total Online Orders],
b.[Total InStore Orders],
coalesce(a.[Total Online Orders] + b.[Total InStore Orders]) / 2 as [Average Order Size]
from table_a a
full outer join table_b b on a.[customer number]=b.[customer number]
Results table:
Customer Number
Total Online Orders
Total InStore Orders
Average Order Size
123456789
1350
350
850
987654321
650
NULL
NULL
I basically want the results table to show 650 for customer 987654321. Any ideas what I am doing wrong?
thanks!
You can use the brute force method:
( coalesce(a.[Total Online Orders], 0) + coalesce(b.[Total InStore Orders], 0)) /
nullif(case when a.[Total Online Orders] is not null then 1 else 0 end +
case when b.[Total InStore Orders] is not null then 1 else 0 end, 0)
)
) as [Average Order Size]
Use COALESCE() for the values of the 2 columns twice:
(
coalesce(a.[Total Online Orders], b.[Total InStore Orders]) +
coalesce(b.[Total InStore Orders], a.[Total Online Orders])
) / 2 as [Average Order Size]
Consider UNION as well, which handles a few other cases too, especially where customer number isn't necessarily unique in each table:
WITH cte (xtype, [customer number], order_amt) AS (
select 1 AS xtype, [customer number], [Total Online Orders] FROM table_a UNION ALL
select 2 AS xtype, [customer number], [Total InStore Orders] FROM table_b
)
SELECT [customer number]
, SUM(CASE WHEN xtype = 1 THEN order_amt ELSE 0 END) AS [Total Online Orders]
, SUM(CASE WHEN xtype = 2 THEN order_amt ELSE 0 END) AS [Total InStore Orders]
, AVG(order_amt) AS [Average Order Size]
FROM cte
GROUP BY [customer number]
ORDER BY [customer number]
;

SQL - Using CUBE grand total per row

Here is my code:
SELECT
ISNULL (CONVERT(VARCHAR, MONTH(PurchaseDate)), NULL) [Month],
ISNULL (Brand, CASE
WHEN MONTH(PurchaseDate) IS NOT NULL THEN 'Monthly SubTotal'
WHEN Brand IS NULL THEN 'Grand Total'
ELSE 'N/A'
END) [Brand], SUM(Price) [Total Amount]
FROM
[dbo].[Purchase_Items]
GROUP BY
MONTH(PurchaseDate), Brand WITH CUBE
I want to change it to Grand Total on selected box. How to code it or change the string on it.
If you first get your data (a simpler version of what you have above) you can then use that as a data source to do conversions/updates as needed.
I'm using a CTE here, but you can do it with subqueries just as well.
WITH MonthTotals AS
(SELECT
MONTH(PurchaseDate) [Month],
[Brand],
SUM(Price) [Total Amount]
FROM [dbo].[Purchase_Items]
GROUP BY MONTH(PurchaseDate), Brand WITH CUBE
)
SELECT CONVERT(VARCHAR(2), mt.[Month]) AS [Month],
CASE WHEN mt.[Month] IS NULL AND mt.[Brand] IS NULL THEN 'Grand Total'
WHEN mt.[Month] IS NULL THEN 'Grand total for ' + mt.[Brand]
WHEN mt.[Brand] IS NULL THEN 'Monthly total'
ELSE mt.[Brand] END AS [Brand]
[Total Amount]
FROM MonthTotals mt;
Note though that CUBE is usually done in SQL Server like the following - it means you can select which columns you CUBE by (or rollup, etc)
GROUP BY CUBE(MONTH(PurchaseDate), Brand)
IMPORTANT UPDATE following #MartinSmith's comment below
Martin Smith gave the advice that I should use the GROUPING function. In reviewing that function, he is 100% correct (and thankyou Martin - this is my learning for today).
For reference, the GROUPING function indicates (with a 1 or 0) whether the row is an aggregate row or not (e.g., one of the rows added by ROLLUP/CUBE/GROUPING SETs).
I also made a mistake with subtotals for months - put it in the wrong column.
Therefore, the update should be the following (note also that I have included the 'original' vales from the CUBE for month and brand as well)
WITH MonthTotals AS
(SELECT
MONTH(PurchaseDate) [Month],
[Brand],
SUM(Price) [Total Amount],
GROUPING(MONTH(PurchaseDate)) AS Agg_flag_Month,
GROUPING([Brand]) AS Agg_flag_Brand
FROM [dbo].[Purchase_Items]
GROUP BY CUBE(MONTH(PurchaseDate), Brand)
)
SELECT [Month] AS Orig_Month,
[Brand] AS Orig_Brand,
CASE WHEN Agg_flag_Month = 1 THEN 'Grand total for ' + mt.[Brand]
ELSE CONVERT(VARCHAR(2), mt.[Month])
END AS [Month],
CASE WHEN Agg_flag_Month * Agg_flag_Brand = 1 THEN 'Grand Total'
WHEN Agg_flag_Brand = 1 THEN 'Monthly total'
ELSE mt.[Brand]
END AS [Brand],
[Total Amount]
FROM MonthTotals mt;

mssql: add column with the same value for all rows to search results

I have my query:
SELECT [Shipment Date], [Amount] as [Running Costs], Sum([Amount]) OVER
(ORDER BY [Shipment Date]) as [Total Running Costs]
FROM...
This gets me 3 columns:
Shipment Date | Running Costs | Total Running Costs
I would like to add a fourth column to this query which has the same value for all rows, and the same number of rows as my original query results.
I know you could add for example '999'as Something to the search results, but how can I do the same for a sum of another column (example: Imagine the total sum of the a column in another table is 1500, and I want to have 1500 for all rows in the fourth column. Something like select sum(column_name)?
The database engine is MSSQL.
You can use a nested query
SELECT [Shipment Date], [Amount] as [Running Costs], [Total Running Costs], SUM([Total Running Costs] OVER ())
FROM
(
SELECT [Shipment Date], [Amount] as [Running Costs], Sum([Amount]) OVER
(ORDER BY [Shipment Date]) as [Total Running Costs]
FROM...
)
Nested window function should also work
SUM(SUM([Running costs]) OVER (ORDER BY [Shipment Date])) OVER ()

SUM of columns from different tables

here is my data,
Table 1:
STORAGE HANDLING TOTAL BILLING
--------------------------------------
1300 10900
0 10950
0 6000
0 5950
Table 2:
LINER REVENUE
---------------
1300
250
3000
200
I need to calculate Total Billing:
I tried with this code.
UPDATE [dbo].[FCLOverall] SET [Total Revenue] = SELECT SUM([STORAGE]), SUM([HANDLING]), SUM([LINER Revenue])
FROM (SELECT [STORAGE], [HANDLING],[Container No]
FROM [dbo].[FCLOverall]
UNION ALL
SELECT [Container No],[LINER Revenue]
FROM [dbo].[FCL_Child])
It is throwing some error missing brackets and invalid keyword select. is the query is right or wrong?
Can someone guide a query how to calculate on this?
does you find something below
UPDATE [dbo].[FCLOverall]
SET [Total Revenue] =
(SELECT SUM([STORAGE])+ SUM([HANDLING]) + SUM([LINER Revenue] ) as s
FROM (
SELECT [Container No],[STORAGE], [HANDLING],0
FROM [dbo].[FCLOverall]
UNION ALL
SELECT [Container No],0,0,[LINER Revenue]
FROM [dbo].[FCL_Child]
) t )
Give this a try based on the assumption that Container No is key field.
UPDATE U
SET U.[Total Revenue] = COALESCE(U.Storage,0) + COALESCE(U.Handling,0) + COALESCE(FCLC.[Liner Revenue],0)
FROM dbo.FCLOverall AS U
INNER JOIN dbo.FCL_Child AS FCLC
ON U.[Container No] = FCLC.[Container No]
Try this:
UPDATE FO
SET [FO.Total Revenue] = ISNULL(FO.[STORAGE], 0) + ISNULL(FO.[HANDLING], 0) + ISNULL(FC.[LINER Revenue],0)
FROM [dbo].[FCLOverall] AS FO
INNER JOIN [dbo].[FCL_Child] FC on FO.[FO.Container No] = FC.[Container No]

Dividing two SQL query results

I'm just trying to learn how to take a value from a column, in this case how much JJ spent on product a, and divide it by the sum of the total Product A sales and turn it into a percentage.
My SQL understanding is pretty low level right now, so the simpler the response the better.
SELECT
JJ / Result * 100 AS percentage
FROM
(SELECT
([Product A] AS JJ
FROM [Test].[dbo].[TableA]
WHERE [Customer Name] = 'JJ'
SELECT SUM([Product A]) AS Result
FROM [Test].[dbo].[TableA]
)
--JJ/Result * 100 = ProdAPercentSales)
You could use a case expression to find JJ's purchases, and divide their sum with the total sum:
SELECT SUM(CASE [Customer name] WHEN 'JJ' THEN [Product A] ELSE 0 END) /
SUM([Product A]) * 100 AS [Percentage]
FROM [Test].[dbo].[TableA]