Pivot - how to sum and calculate the outcome - sql

I am sure this is a quick one, but tried everything, well apart from the answer. I have a pivot script which works fine, apart from the result in the columns, I need to divide by 100. So result / 100
Script is
SELECT
USERID AS UserId,APPOINTMENTDATE,
isnull ([1],0) as'other',isnull ([2],0) as 'Medicare'
FROM
(SELECT invoices.USERID, APPOINTMENTDATE,
[total],PAYERCODE,users.LOCATIONID
FROM APPOINTMENTS
where
APPOINTMENTDATE between '2017-01-22' and '2017-01-23'
) AS SourceTable
PIVOT
(
Sum(total)
FOR PAYERCODE IN ([1], [2])
) AS PivotTable;
So what I would like to do is :
Sum(total) change to something like Sum(total/100)
Any thoughts..
Cheers

Added this sample as it works. Heres the fiddle: http://sqlfiddle.com/#!6/8eef1/1/0
The issue with your sample code is that you are trying to do a select on the table itself rather than the Pivot. You will need to define your columns inside your 'SourceTable' and then Pivot the PayerCode and then do your Select * FROM (Sourcetable Pivottable)
drop table TestingPivot
Create table TestingPivot
( Total INT,
Payercode INT,
LocationID INT,
UserID INT,
Name VARCHAR(100) )
Insert into TestingPivot values(100, 1, 1, 1, 'Ryan')
Insert into TestingPivot values(200, 2, 2, 2, 'Mike')
Insert into TestingPivot values(300, 3, 3, 3, 'John')
Select * from (
Select Total/100 as NewTotal, PayerCode, UserID, LocationID,
case when PayerCode = 1 then 'Other'
when PayerCode = 2 then 'Medicare'
else ''
end as Type
from TestingPivot
) as t
Pivot
(
Sum(NewTotal)
FOR PayerCode IN ("1","2")
) as P;

Related

Combining rows and columns in SQL

I am trying to convert my rows into columns, or my columns into rows... I am a little confused with which it is exactly but here's what I would want it to look like
Original table:
Month | Price
1 500
2 600
3 700
what it needs to look like:
1 2 3
500 600 700
Could anyone tell me how his could be done?
EDIT:
CREATE table #yourtable (
[Id] int,
[Value] varchar(6),
[ColumnName] varchar(13)) ;
INSERT INTO #yourtable (
[Id],
[Value],
[ColumnName])
VALUES
(1, '1', 'Month'),
(2, '500', 'Price') ;
select
Month,
Price
from (
select
value,
columnname
from #yourtable ) d
pivot
(max(value) for columnname in (Month, Price) ) piv;
You wrote an almost correct query.
select
Month,
Price
from (
select
value,
columnname
from #yourtable) d
pivot
(max(value) for columnname in ('Month' AS Month, 'Price' AS Price) ) piv;

SQL Insert row when a cell does not contain a specific set of characters

My database has a column named Group.
This Group can be one of two values:
Group101 = Main group
Group101D1 = Subgroup
Every group has two options like this.
But I have some situations where Group101D1 exists but Group101 does not.
Now I want to create an insert where I search for groups with D1 that doesn't have a main group. for example I have Group105D1 but don't have Group105. I want an insert to create a row with Group105.
This is as far as I have come:
INSERT INTO (Group)
SELECT [Table1].[Group], [Table2].[Group]
FROM [Table] Table1
INNER JOIN [Table] Table2 ON [table1].[Group] = [Table2].[Group]
-- WHERE [Table2].[Group] LIKE '%D1'
-- AND [Table1].[Group] NOT LIKE '%D1'
Can some of you please help, I don't know how to finish this.
I know I probably need to use inner join, replace and a where not clause.
You will need replace Also query should exclude rows already exists
Sample data:
DECLARE #groups TABLE ([Group] VARCHAR(100), description VARCHAR(100))
INSERT #groups ([Group], description)
SELECT 'Group101', 'Something1'
UNION ALL
SELECT 'Group101d1', 'Something1'
UNION ALL
SELECT 'Group105d1', 'description_Bleh'
UNION ALL
SELECT 'Group2054', 'desc_2054'
UNION ALL
SELECT 'Group2054d1', 'desc_2054'
Use replace function and exclude Maingroup if it exists
SELECT Replace([group], 'd1', '') [Group], description
FROM #groups
WHERE [Group] NOT IN (
SELECT p.[Group]
FROM #groups g
INNER JOIN #groups p
ON g.[Group] = replace(p.[Group], 'd1', '')
)
Result:
Group description
Group105 description_Bleh
If all subgroups ends with "D1" you can use below query to insert missing main groups.
INSERT INTO (Group)
SELECT
left(subtable.Group,(len(subtable.Group)-len('D1')))
FROM
[Table1].[Group] subtable
where
charindex ( 'D1', subtable.Group) > 0 -- if it is sub-record
and
not exists --check if main group exists
(SELECT
1
FROM
[Table1].[Group] main
where (charindex ( main.Group+'D1', subtable.Group) != 0)
)
Stuff you have already just packaged with data
DECLARE #groups TABLE (grp VARCHAR(100), description VARCHAR(100));
INSERT #groups (grp, description) values
('Group101', 'Something1')
, ('Group101d1', 'Something1')
, ('Group105d1', 'description_Bleh')
, ('Group106d1', 'description_Bleh6')
, ('Group2054', 'desc_2054')
, ('Group2054d1', 'desc_2054');
select * from #groups order by grp;
insert into #groups
select replace(g1.grp, 'd1', ''), g1.description
from #groups g1
where g1.grp like '%d1'
and not exists ( select 1
from #groups g2
where g2.Grp = replace(g1.grp, 'd1', '')
);
select * from #groups order by grp;
You can use NOT EXISTS and REPLACE to get the desired results like below :
INSERT INTO Table2(Group)
select replace([Group], 'd1', '') from Table1 a
where [Group] like '%d1' and
not exists(
select 1 from Table1 where [group] = replace(a.[Group], 'd1', '')
)
I did it this way in the end!
insert into Table (Group, Description)
select replace(Group,'D1','') , description from Table
where Group like '%D1'
and replace(Group,'D1','') not in (
select Group from Table
where Group like 'Group%' and Group not like '%D1')

Show sum Column SQL code

I need show sum col(item) under col with SQL code ? it's possible
Code item
---- ----
1 30
3 40
4 50
9 80
---- ----
Total 200
Use Rollup to get the summary row
SELECT CASE
WHEN Grouping(code) = 1 THEN 'Total'
ELSE Cast(code AS VARCHAR(50))
END,
Sum(item)
FROM Yourtable
GROUP BY code WITH rollup
DECLARE #Table1 TABLE
(Code int, item int)
;
INSERT INTO #Table1
(Code, item)
VALUES
(1, 30),
(3, 40),
(4, 50),
(9, 80)
;
Script :
select Code , sum(item)item
from #Table1
group by GROUPING SETS((Code) , ())
order by Code DESC
select * from (select * from #Table1
union
select null, sum(item) item from #Table1)a
order by item
Select
Code,
item
from
# table_name
Union All
select
Null,
sum(item)item
from
# table_name
As we are using union all so distinct and order by operation will be saved.

How to replace the 'Strings' with numerical values based on a group by clause

I have the below table (#temp1) where I need to replace the string in the column'Formula' with the matching input 'VALUE' column based on the group 'Yearmonth'.
The 'Formula' column may be of any mathematical expression for better understanding I have mentioned a simple example below.
IDNUM formula INPUTNAME VALUE YEARMONTH
---------------------------------------------------------------------
1 imports(398)+imports(399) imports(398) 17.000 2003:1
2 imports(398)+imports(399) imports(398) 56.000 2003:2
3 imports(398)+imports(399) imports(399) 15.000 2003:1
4 imports(398)+imports(399) imports(399) 126.000 2003:2
For eg :From the above table i need the output as
Idnum Formula Yearmonth
1. 17.00 +15.00 2003:1
2. 56.00 +126.00 2003:2
I tried with the below different query from various suggestions but coludnt achieve it. Could someone help me this out ?
Type1 :
SELECT
REPLACE(FORMULA, INPUTName, AttributeValue) AS realvalues,
yearmonth
FROM #temp1
GROUP BY yearmonth
TYPE2 :
USING XML PATH... In this case it got worked but I need to replace only the strings with the values and not to stuff the strings based on mathematcal operation.(Because the formula might be of any type).
SELECT
IDNUM = MIN(IDNUM),
FORMULA =
(SELECT STUFF(
(SELECT ' +' + CONVERT(VARCHAR(10), Value)
FROM #temp1
WHERE YEARMONTH = t1.YEARMONTH
FOR XML PATH(''))
,1, 2, '')),
YEARMONTH
FROM #TEMP1 t1
GROUP BY YEARMONTH
TYPE3:Using Recursions...This is returning only the null values...
;with t as (
select t.*,
row_number() over (partition by yearmonth order by idnum) as seqnum,
count(*) over (partition by yearmonth) as cnt
from #temp1 t
)
,cte as (
select t.seqnum, t.yearmonth, t.cnt,
replace(formula, inputname, AttributeValue) as formula1
from t
where seqnum = 1
union all
select cte.seqnum, cte.yearmonth, cte.cnt,
replace(CTE.formula1, T.inputname, T.AttributeValue) as formula2
from cte join
t
on cte.yearmonth = t.yearmonth
AND cte.seqnum = t.seqnum + 1
)
select row_number() over (order by (select null)) as id,formula1
from cte
where seqnum = cnt
This is full working example using recursive CTE:
DECLARE #DataSource TABLE
(
[IDNUM] TINYINT
,[formula] VARCHAR(MAX)
,[INPUTNAME] VARCHAR(128)
,[VALUE] DECIMAL(9,3)
,[YEARMONTH] VARCHAR(8)
);
INSERT INTO #DataSource ([IDNUM], [formula], [INPUTNAME], [VALUE], [YEARMONTH])
VALUES ('1', 'imports(398)+imports(399)', 'imports(398)', '17.000', '2003:1')
,('2', 'imports(398)+imports(399)', 'imports(398)', '56.000', '2003:2')
,('3', 'imports(398)+imports(399)', 'imports(399)', '15.000', '2003:1')
,('4', 'imports(398)+imports(399)', 'imports(399)', '126.000', '2003:2')
,('5', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(391)', '5.000', '2003:3')
,('6', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(392)', '10.000', '2003:3')
,('7', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(393)', '3.000', '2003:3')
,('8', '(imports(391)+imports(392)-imports(393))/imports(394)', 'imports(394)', '-5.000', '2003:3');
WITH DataSource AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY [YEARMONTH] ORDER BY [IDNUM]) AS [ReplacementOrderID]
,[YEARMONTH]
,[formula]
,[INPUTNAME] AS [ReplacementString]
,[VALUE] AS [ReplacementValue]
FROM #DataSource
),
RecursiveDataSource AS
(
SELECT [ReplacementOrderID]
,[YEARMONTH]
,REPLACE([formula], [ReplacementString], [ReplacementValue]) AS [formula]
FROM DataSource
WHERE [ReplacementOrderID] = 1
UNION ALL
SELECT DS.[ReplacementOrderID]
,DS.[YEARMONTH]
,REPLACE(RDS.[formula], DS.[ReplacementString], DS.[ReplacementValue]) AS [formula]
FROM RecursiveDataSource RDS
INNER JOIN DataSource DS
ON RDS.[ReplacementOrderID] + 1 = DS.[ReplacementOrderID]
AND RDS.[YEARMONTH] = DS.[YEARMONTH]
)
SELECT RDS.[YEARMONTH]
,RDS.[formula]
FROM RecursiveDataSource RDS
INNER JOIN
(
SELECT [YEARMONTH]
,MAX([ReplacementOrderID]) AS [ReplacementOrderID]
FROM DataSource
GROUP BY [YEARMONTH]
) DS
ON RDS.[YEARMONTH] = DS.[YEARMONTH]
AND RDS.[ReplacementOrderID] = DS.[ReplacementOrderID]
ORDER BY RDS.[YEARMONTH]
Generally, you simply want to perform multiple replacements over a string in one statement. You can have many replacement values, just play with the MAXRECURSION option.
--Create sample data
DROP TABLE #temp1
CREATE TABLE #temp1 (IDNUM int, formula varchar(max), INPUTNAME varchar(max), VALUE decimal, YEARMONTH varchar(max))
INSERT INTO #temp1 VALUES
(1, 'imports(398)+imports(399)', 'imports(398)', 17.000, '2003:1'),
(2, 'imports(398)+imports(399)', 'imports(398)', 56.000, '2003:2'),
(3, 'imports(398)+imports(399)', 'imports(399)', 15.000, '2003:1'),
(4, 'imports(398)+imports(399)', 'imports(399)', 126.000, '2003:2')
--Query
;WITH t as (
SELECT formula, YEARMONTH, IDNUM
FROM #temp1
UNION ALL
SELECT REPLACE(a.formula, b.INPUTNAME, CAST(b.VALUE AS varchar(100))) AS formula, a.YEARMONTH, a.IDNUM
FROM t a
JOIN #temp1 b ON a.YEARMONTH = b.YEARMONTH AND a.formula LIKE '%' + b.INPUTNAME + '%'
)
SELECT MIN(IDNUM) AS IDNUM, formula, YEARMONTH
FROM t
WHERE formula not LIKE '%imports(%'
GROUP BY formula, YEARMONTH

Unpivot table with multiple columns and dynamic column names

I am trying to unpivot a table with multiple rows and columns. Each row needs to be extratced to 2 rows with specific columns and the column names need to be renamed and a new column needs to added based on the columns selected!
I am including before and after sample data and a script to setup the data.
CREATE TABLE #tmpProducts (
ProductId INT,
ProductName nVARCHAR(100),
B2B_GrossRevenue DECIMAL(10,2),
B2B_DirectCost DECIMAL(10,2),
B2B_NetRevenue DECIMAL(10,2),
B2C_GrossRevenue DECIMAL(10,2),
B2C_DirectCost DECIMAL(10,2),
B2C_NetRevenue DECIMAL(10,2)
)
INSERT INTO #tmpProducts SELECT 1, 'Product1',1545.00,406.25,1138.75,195.00,35.10,159.90
INSERT INTO #tmpProducts SELECT 2, 'Product2',902.00,189.00,713.00,3280.00,590.40,2689.60
INSERT INTO #tmpProducts SELECT 3, 'Product3',15665.00,3988.39,11676.61,6247.00,1124.46,5122.54
INSERT INTO #tmpProducts SELECT 4, 'Product4',736.00,196.16,539.84,2395.00,431.10,1963.90
SELECT * FROM #tmpProducts
DROP TABLE #tmpProducts
CREATE TABLE #tmpProducts2 (
ProductId INT,
ProductName nVARCHAR(100),
[Type] nVARCHAR(3),
GrossRevenue DECIMAL(10,2),
DirectCost DECIMAL(10,2),
NetRevenue DECIMAL(10,2)
)
INSERT INTO #tmpProducts2 SELECT 1, 'Product1','B2B',1545.00,406.25,1138.75
INSERT INTO #tmpProducts2 SELECT 1, 'Product1','B2C',195.00,35.10,159.90
INSERT INTO #tmpProducts2 SELECT 2, 'Product2','B2B',902.00,189.00,713.00
INSERT INTO #tmpProducts2 SELECT 2, 'Product2','B2C',3280.00,590.40,2689.60
INSERT INTO #tmpProducts2 SELECT 3, 'Product3','B2B',15665.00,3988.39,11676.61
INSERT INTO #tmpProducts2 SELECT 3, 'Product3','B2C',6247.00,1124.46,5122.54
INSERT INTO #tmpProducts2 SELECT 4, 'Product4','B2B',736.00,196.16,539.84
INSERT INTO #tmpProducts2 SELECT 4, 'Product4','B2C',2395.00,431.10,1963.90
SELECT * FROM #tmpProducts2
DROP TABLE #tmpProducts2
I have attempted this but i can't get past the second column and im not sure how at add a new column with specific text, (probably dynamic sql but trying to avoid this if possible)
Here is the start of my attempt, any help would be much appreciated.
SELECT ProductId, ProductName,GrossRevenue
FROM (
SELECT ProductId, ProductName, B2B_GrossRevenue,B2C_GrossRevenue FROM #tmpProducts
) as t
UNPIVOT ( GrossRevenue for test IN (B2B_GrossRevenue,B2C_GrossRevenue)) AS unpvt
You just keep unpivoting
SELECT ProductId,ProductName, Substring(col1,1,3) as type, GrossRevenue, DirectCost, NetRevenue
FROM (
SELECT * FROM #tmpProducts
) as t
UNPIVOT ( GrossRevenue for col1 IN (B2B_GrossRevenue,B2C_GrossRevenue)) AS unpvt
unpivot ( DirectCost for col2 in (B2b_DirectCost, B2c_DirectCost)) up2
unpivot ( NetRevenue for col3 in (B2b_NetRevenue, B2c_NetRevenue)) up3
where SUBSTRING(col1,1,3)=SUBSTRING(col2,1,3)
and SUBSTRING(col1,1,3)=SUBSTRING(col3,1,3)
and join on the col columns to filter out mismatches
Here is a way to do this using Dynamic SQL. This will allow you to get all of the columns upon execution. Then you will not have to alter the query if you get any data changes. This does both an UNPIVOT and PIVOT:
DECLARE #colsUnPivot AS NVARCHAR(MAX),
#colsPivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #colsUnPivot = stuff((select ','+quotename(C.name)
from sys.columns as C
where C.object_id = object_id('tmpProducts') and
C.name like 'B2%'
for xml path('')), 1, 1, '')
SET #colsPivot = stuff((select DISTINCT ','+quotename(right((C.name), len(C.name)-4))
from sys.columns as C
where C.object_id = object_id('tmpProducts') and
C.name like 'B2%'
for xml path('')), 1, 1, '')
set #query
= ' SELECT ProductId, ProductName, [type], ' + #colsPivot +'
FROM
(
SELECT ProductId, ProductName, substring(field, 1, 3) [type]
, value, right((field), len(field)-4) as col
from tmpProducts
unpivot
(
value
for field in (' + #colsUnPivot + ')
) unpvt
) x
PIVOT
(
sum(value)
FOR col IN (' + #colsPivot +')
)p'
execute(#query)
See SQL Fiddle with Demo
If you have multiple groups that you're looking to pivot around you can also do something like this:
Select *
from table
unpivot include nulls ( (test_name, test_date) for col_nm in ( (test1, date1) as 'test_val1'
,(test2, date2) as 'test_val2'
,(test3, date3) as 'test_val3'
)
)