How to combine rows into one, MS SQL Server management Studio - sql

I think this is a tricky one, How do you combine all of these rows into one? Is it possible? Maybe using temp tables, the values on the left from combo onwards are null but could contain a value. Any ideas? Let me know if you've got any questions.
I would like to show just one line for this unit, i.e/ RecordNumber Reg_string Parts Materials Labour Combo Smart Total Estimate. Record number does not need to be selected in the query but might help when building the script. This is my script so far.
RecordNumber Reg_string Parts Materials Labour Combo Smart Total Estimate
1 AB12ABC NULL NULL NULL 222.27 0 222.27
2 AB12ABC NULL NULL NULL 76.7 0 76.7
3 AB12ABC NULL NULL NULL 48.1 0 48.1
4 AB12ABC NULL NULL NULL 49.4 0 49.4
5 AB12ABC NULL NULL 12 NULL 1 13
6 AB12ABC NULL NULL NULL 255 NULL 255
7 AB12ABC NULL NULL NULL 255 NULL 255
I would like the output to be like this please:
RecordNumber Reg_string Parts Materials Labour Combo Smart Total Estimate
1 AB12ABC NULL NULL 12 906.47 1 919.47
My script is this if it helps:
SELECT UnitData_Vehicle.Reg_String AS Registration, UnitData_Vehicle.VehID_String AS [Vendor Code], UnitData_Vehicle.Manu_String AS Make,
UnitData_Vehicle.ManuNS_String AS [Make NS], SUM(CONVERT(money, UnitData_Vehicle_CompCond.Materials_String)) AS [Materials Price],
CONVERT(money, UnitData_Vehicle_CompCond.Labour_String) AS [Labour Price], CONVERT(money, UnitData_Vehicle_CompCond.Combo_String)
AS [Combination Price], CONVERT(money, UnitData_Vehicle_CompCond.PartSpend_String) AS [Parts Price], CONVERT(money,
UnitData_Vehicle_CompCond.SmartRep_String) AS [Smart Price], CONVERT(money, UnitData_Vehicle_CompCond.Estimate_String)
AS [Estimate EX VAT]
FROM UnitData_Vehicle INNER JOIN
UnitData_Vehicle_CompCond ON UnitData_Vehicle.InspectionResultId = UnitData_Vehicle_CompCond.InspectionResultId
WHERE (UnitData_Vehicle.InspectionProcedureName LIKE '%- inspection') AND (DATEDIFF(day, UnitData_Vehicle.InspectionDateTime, GETDATE()) = 2)
AND Reg_String = 'AB12ABC'
GROUP BY UnitData_Vehicle.EstimDate_DateTime, UnitData_Vehicle.Reg_String, UnitData_Vehicle.VehID_String, UnitData_Vehicle.Manu_String,
UnitData_Vehicle.ManuNS_String, CONVERT(money, UnitData_Vehicle_CompCond.Labour_String), CONVERT(money,
UnitData_Vehicle_CompCond.Combo_String), CONVERT(money, UnitData_Vehicle_CompCond.PartSpend_String), CONVERT(money,
UnitData_Vehicle_CompCond.SmartRep_String), CONVERT(money, UnitData_Vehicle_CompCond.Estimate_String)

SELECT
UnitData_Vehicle.Reg_String AS Registration,
UnitData_Vehicle.VehID_String AS [Vendor Code],
UnitData_Vehicle.Manu_String AS Make,
UnitData_Vehicle.ManuNS_String AS [Make NS],
SUM(CONVERT(money, UnitData_Vehicle_CompCond.Materials_String)) AS [Materials Price],
SUM(CONVERT(money, UnitData_Vehicle_CompCond.Labour_String)) AS [Labour Price],
SUM(CONVERT(money, UnitData_Vehicle_CompCond.Combo_String)) AS [Combination Price],
SUM(CONVERT(money, UnitData_Vehicle_CompCond.PartSpend_String)) AS [Parts Price],
SUM(CONVERT(money, UnitData_Vehicle_CompCond.SmartRep_String)) AS [Smart Price],
SUM(CONVERT(money, UnitData_Vehicle_CompCond.Estimate_String)) AS [Estimate EX VAT]
FROM UnitData_Vehicle INNER JOIN UnitData_Vehicle_CompCond
ON UnitData_Vehicle.InspectionResultId = UnitData_Vehicle_CompCond.InspectionResultId
WHERE (UnitData_Vehicle.InspectionProcedureName LIKE '%- inspection') AND (DATEDIFF(day, UnitData_Vehicle.InspectionDateTime, GETDATE()) = 2) AND Reg_String = 'AB12ABC'
GROUP BY UnitData_Vehicle.EstimDate_DateTime, UnitData_Vehicle.Reg_String, UnitData_Vehicle.VehID_String, UnitData_Vehicle.Manu_String,UnitData_Vehicle.ManuNS_String

Your query is huge and hard to read, but what you need to essentially do is SUM the columns add add a "GROUP BY Reg_string" to the end of your query, obviously do not include the "RecordNumber" in your output as it can not be grouped.

Your query isn't very easy to read, but this is essentially what you'd have to do if all of your fields were in the same table, just amend it to do what you need regarding table joins etc...
SELECT Reg_String),
SUM(Parts) As Parts,
SUM(Materials) AS Materials,
SUM(Labour) AS Labour,
SUM(Combo) AS Combo,
SUM(Smart) AS Smart,
SUM(TotalEstimate) AS TotalEstimate
FROM MyTable
WHERE Reg_String = 'AB12ABC'
GROUP BY Reg_String

If I am not committing mistake , Total Estimate = Labour + Combo + Smart ?
Below is the query
SELECT Reg_String,
SUM(Parts) As Parts,
SUM(Materials) AS Materials,
SUM(Labour) AS Labour,
SUM(Combo) AS Combo,
SUM(Smart) AS Smart,
SUM(Labour + Combo + Smart) AS TotalEstimate
FROM MyTable
GROUP BY Reg_String

SELECT MAX(Reg_String),
SUM(Parts) As Parts,
SUM(Materials) AS Materials,
SUM(Labour) AS Labour,
SUM(Combo) AS Combo,
SUM(Smart) AS Smart,
SUM(Labour + Combo + Smart) AS TotalEstimate
FROM MyTable
GROUP BY Reg_String
use MAX(Reg_String) to display Reg_String also since max will return same result because query is grouping by Reg_String

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]
;

How do I join these 3 tables, do a sum calculation and group by multiple values?

So I have these 3 tables below:
User Table:
Deposit Table:
Withdrawal Table:
Question:
How do I join these 3 tables together, having the values grouped by:
Month
Sex
Age
State
Expected Output:
As seen from my expected output above, I want to separate these users into different buckets
i.e.
Month: January, Sex: F, Age: 18, State: Arizona (Bucket 1)
Month: January, Sex: M, Age: 21, State: Texas (Bucket 2)
and find the sum(Deposit.amount) & sum (Withdrawal.amount) group by the fields above ^
as well as how many users are in this bucket.
Clarification:
"Month" column in my Expected Ouput is based on Transaction Month for both Deposit & Withdrawal table combined, I just added the "Account Created Month" column in User table just in case its possible to do a 3-table join through Month values.
This should work:
SELECT tr.Month, u.Sex, u.Age, u.Stage
, Sum(CASE WHEN [Type] = 'D' THEN tr.Amount ELSE 0 END) As [Total Deposit Amount]
, Sum(CASE WHEN [Type] = 'W' THEN tr.Amount ELSE 0 END) As [Total Withdrawal Amount]
, COUNT(distint u.UserID) As [Number of Users in this Category]
FROM (
SELECT userid, [Deposit Amount] As Amount, [Transaction Month] As Month, 'D' As [Type] FROM [Deposit]
UNION ALL
SELECT userid, [Withdrawal Amount], [Transaction Month], 'W' FROM [Withdrawal]
) tr
INNER JOIN User u ON u.UserID = tr.UserId
GROUP BY tr.Month, u.Sex, u.Age, u.State
Really, deposits and withdrawals should be the same table (Transactions) to begin with, where the only difference is withdrawals are negative.
Also... please stop using images to represent your sample data and results. It makes things so much harder on us to help you, which makes it less likely you'll get a good or prompt answer.

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;

Query to pick preferred available row in SQL

I use SQL server.
I currently have a table which contains several items, some of them have a price and some not.
However some of them have several prices columns: “Commercial price”, “Current price”, “New price”
It is possible that for some of the items not all of the 3 pricing columns above exist, and some only have “Current price” and the rest is NULL.
So I need the query to check which one of the prices columns exist/isn’t null, by the following “priority”
New price > Current price > Commercial price
(That means that if “New price” doesn’t exist or is NUll, the query will pick the price from “Current price”)
And in the end to add a row/columns which is named “Total” and calculates all the prices together.
Thanks a lot!
SELECT COALESCE([New price],[Current price],[Commercial price]) as Price
For the last part you could add a UNION with another select (possibly grouped by product or whatever), something like:
SELECT SUM(ISNULL([New Price], 0) + ISNULL([Current price], 0) + ISNULL(Commercial price], 0) AS Total
SELECT ID, SUM(ISNULL([New Price], 0) + ISNULL([Current price], 0) + ISNULL(Commercial price], 0) AS TotalPrice FROM YOURTABLE
GROUP BY ID
UNION
SELECT COUNT(ID), SUM(ISNULL([New Price], 0) + ISNULL([Current price], 0) + ISNULL(Commercial price], 0) AS TotalPrice FROM YOURTABLE

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]