Convert Access Transform/Pivot Query to SQL Server

Convert Access TRANSFORM/PIVOT query to SQL Server

Here is the equivalent version using the PIVOT table operator:

SELECT *
FROM
(
SELECT
CASE
WHEN sumUnits > 0
THEN SumAvgRent / sumUnits ELSE 0
END AS Expr1,
Description,
Period
FROM temp
) t
PIVOT
(
AVG(Expr1)
FOR Period IN(Period1, Period2, Period3)
) p;

SQL Fiddle Demo

For instance, this will give you:

| DESCRIPTION | PERIOD1 | PERIOD2 | PERIOD3 |
---------------------------------------------
| D1 | 10 | 0 | 20 |
| D2 | 100 | 1000 | 0 |
| D3 | 50 | 10 | 2 |

Note that When using the MS SQL Server PIVOT table operator, you have to enter the values for the pivoted column. However, IN MS Access, This was the work that TRANSFORM with PIVOT do, which is getting the values of the pivoted column dynamically. In this case you have to do this dynamically with the PIVOT operator, like so:

DECLARE @cols AS NVARCHAR(MAX);
DECLARE @query AS NVARCHAR(MAX);

SELECT @cols = STUFF((SELECT distinct
',' +
QUOTENAME(Period)
FROM temp
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');

SET @query = ' SELECT Description, ' + @cols + '
FROM
(
SELECT
CASE
WHEN sumUnits > 0
THEN SumAvgRent / sumUnits ELSE 0
END AS Expr1,
Description,
Period
FROM temp
) t
PIVOT
(
AVG(Expr1)
FOR Period IN( ' + @cols + ')
) p ';

Execute(@query);

Updated SQL Fiddle Demo

This should give you the same result:

| DESCRIPTION | PERIOD1 | PERIOD2 | PERIOD3 |
---------------------------------------------
| D1 | 10 | 0 | 20 |
| D2 | 100 | 1000 | 0 |
| D3 | 50 | 10 | 2 |

Convert MS Access TRANSFORM/PIVOT query to SQL Server

I have such universal stored procedure for pivoting

CREATE PROCEDURE [dbo].[msrTransformAsAccessDo]
@TRANSFORM_Function nvarchar(max),
@TRANSFORM_Field nvarchar(max),
@SQL_SELECT nvarchar(max),
@SQL_FROM_WHERE nvarchar(max),
@SQL_GROUPBY_HAVING_ORDERBY nvarchar(max),
@PIVOTBY nvarchar(max)
AS
BEGIN
SET NOCOUNT ON

DECLARE @DynSQL nvarchar(max)

SET @DynSQL = N' SELECT DISTINCT ' + @PIVOTBY + ' as key_value into ##pivoting ' + @SQL_FROM_WHERE + ' ORDER BY ' + @PIVOTBY

DROP TABLE IF EXISTS ##pivoting
EXEC (@DynSQL)

DECLARE @Values nvarchar(max) = N''
DECLARE @tmpStr nvarchar(max)
DECLARE @rsk CURSOR

SET @rsk = CURSOR SCROLL
FOR
select key_value from ##pivoting
OPEN @rsk
FETCH NEXT FROM @rsk INTO @tmpStr
WHILE @@FETCH_STATUS = 0
BEGIN
SET @Values = @Values + ', ' + @TRANSFORM_Function + '(Case When convert(nvarchar,' + @PIVOTBY + ')=convert(nvarchar,''' + @tmpStr + ''') Then ' + @TRANSFORM_Field + ' Else Null End) AS [' + @tmpStr + '] '
FETCH NEXT FROM @rsk INTO @tmpStr
END
CLOSE @rsk

DROP TABLE IF EXISTS ##pivoting

SET @DynSQL = @SQL_SELECT + ' ' + @Values + ' ' + @SQL_FROM_WHERE + ' ' + @SQL_GROUPBY_HAVING_ORDERBY

EXEC (@DynSQL)
END
GO

And call for your case:

EXECUTE msrTransformAsAccessDo 
'Avg',
'[X Avg Sub Group]',
'SELECT Day, Process, PARTNO_VAL0, CTQNO_VAL0, ctq_description, MACHINE_VAL0, usl, lsl, Avg([X Avg Sub Group]) AS [Total Of X Avg Sub Group] ',
'FROM [Capability Data with Shift] WHERE (((Process)=''BBB WELDING'')) ',
'GROUP BY Day, Process, PARTNO_VAL0, CTQNO_VAL0, ctq_description, MACHINE_VAL0, usl, lsl ',
'SHIFT_VAL0'

Convert Access TRANSFORM/PIVOT query to SQL Server 2012

Well I figured it out myself. I am not sure if this will help others but here is the final query that will work in SQL Server. I converted this from MS Access:

SELECT pt.* FROM 
(SELECT SUM(TTQTY * qty) AS quantity, matlprodcode AS product_code, cvend_name AS supplier, CITMCD as material, matldesc AS description, MIN(unit_cost) AS unit_cost, budgetmonth
FROM acs_Budget
WHERE matlprodcode NOT LIKE ';I8*'
AND matlprodcode NOT LIKE 'I1'
GROUP BY matlprodcode, cvend_name, CITMCD, matldesc, budgetmonth) AS src
PIVOT (MIN(quantity) FOR src.budgetmonth IN ([4/1/2015], [5/1/2015], [6/1/2015], [7/1/2015], [8/1/2015], [9/1/2015], [10/1/2015], [11/1/2015], [12/1/2015], [1/1/2016], [2/1/2016], [3/1/2016])) AS pt;

Some things that helped me:

  • First I selected everything that I wanted to see. Including what MS Access was transforming and pivoting.
  • Then I found out what each column MS Access was pivoting, in this case the quantity.
  • So I did a MIN of the quantity because the PIVOT needs an aggregated function.
  • After the aggregated function you need the actual PIVOT that MS Access is using which goes after the FOR.
  • Then I did something similar to a SELECT DISTINCT budgetmonth FROM acs_Budget to get each item I could pivot by and that's where the IN came in.

Not sure if I explained very well but this is how I got mine to work!

Convert Access Crosstab/PIVOT query to T-SQL

IF OBJECT_ID('tmpEmployees_Test', 'U') IS NOT NULL DROP TABLE tmpEmployees_Test;
CREATE TABLE tmpEmployees_Test (EmployeeID INT, EmployeeName VARCHAR(255));
INSERT tmpEmployees_Test (EmployeeID, EmployeeName)
VALUES (1, 'Doe, Jane'), (2, 'Doe, John'), (3, 'Guy, Some');

IF OBJECT_ID('tmpOrders_Test', 'U') IS NOT NULL DROP TABLE tmpOrders_Test;
CREATE TABLE tmpOrders_Test (EmployeeID INT, Customer VARCHAR(255), Date DATE, OrderType VARCHAR(255));
INSERT tmpOrders_Test (EmployeeID, Customer, Date, OrderType)
VALUES (1, 'Fake Customer', '2016-05-14', 'New')
, (2, 'Some Company', '2016-05-13', 'Change')
, (3, 'Stuff Inc.', '2016-05-14', 'New')
, (3, 'Cool Things', '2016-05-12', 'Change')
, (3, 'Amazing Things', '2016-05-12', 'Change');

DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
SET @columns = N'';
SELECT @columns += N', p.' + QUOTENAME(Name)
FROM (SELECT distinct CONVERT(nvarchar(30) , p.Date , 101) as Name FROM dbo.tmpOrders_Test AS p where [Date] > GETDATE()-7
) AS x;
-- Kept it for formatting Purpose
DECLARE @columns1 NVARCHAR(MAX)
SET @columns1 = N'';
SELECT @columns1 += N', ISNULL(p.' + QUOTENAME(Name) + ',''/'') AS ' + QUOTENAME(Name)
FROM (SELECT distinct CONVERT(nvarchar(30) , p.Date , 101) as Name FROM dbo.tmpOrders_Test AS p where [Date] > GETDATE()-7
) AS x;

SET @sql = N'
SELECT EmployeeName, Count(*) as Total ' + @columns1 + '
FROM
(
SELECT EmployeeID, EmployeeName' + ''+ @columns1 + '' + '
FROM
(
SELECT o.employeeID,EmployeeName, CAST(COUNT(case WHEN OrderType = ''New'' then 1 end) as varchar(5)) + ''/'' +
CAST(COUNT(case WHEN OrderType = ''Change'' then 1 end) as varchar(5)) as OrderType, CONVERT(nvarchar(30) , p.Date , 101) as Date
FROM dbo.tmpOrders_Test AS p
INNER JOIN dbo.tmpEmployees_Test AS o
ON p.EmployeeID = o.EmployeeID
GROUP BY EmployeeName, Date, o.employeeID
) AS j
PIVOT
(
Max(OrderType) FOR Date IN ('
+ STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '')
+ ')
) AS p) as p JOIN tmpOrders_Test as m on p.employeeID = m.employeeID
where [Date] > GETDATE()-7
GROUP BY EmployeeName ' + @columns + '
';

PRINT @sql;
EXEC sp_executesql @sql;

This one is using dynamic Pivot. You might want to do this business logic on Application or Reporting Side instead of complex sql.

Convert the Pivot table in MS Access to Pivot table in SQL Server

After looking at the solution provided by @Jonathan Willcock, I was able to make up a solution for your problem. Have a look at this and perhaps you might need to refine it.

USE LinesmanRPL
DECLARE @PrerequisiteColumn AS NVARCHAR(MAX),
@SQLforPivotTable AS NVARCHAR(MAX);
SET @PrerequisiteColumn = STUFF((SELECT distinct ',' + QUOTENAME(Prerequisite)
FROM [UETTDRSB39A Criteria]
WHERE [UETTDRSB39A Criteria].Pathway = 'Common' OR [UETTDRSB39A Criteria].Pathway = 'Electrical'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
SET @SQLforPivotTable = 'SELECT RPLEvidenceOptionsDetail, ' + @PrerequisiteColumn + ' FROM
(
SELECT [RPL Link], RPLEvidenceOptionsDetail, Prerequisite
FROM [UETTDRSB39A Criteria]
) Temp
PIVOT
(
MIN([RPL Link]) FOR Prerequisite IN (' + @PrerequisiteColumn + ')
) PivotTable '
EXECUTE(@SQLforPivotTable)

Convert MS Access count and pivot query into SQL Server

Essentially, this is the classic transpose query. Consider the following SQL which should be compliant in most RDMS's. For MS Access, you would use IIF() instead of CASE WHEN (and parentheses in the joins). The crosstab query with Transform is primarily an MS Access type while Pivot() is primarily an SQL Server function. However, below should work across database dialects.

SELECT 
dbo.Receipts.id_receipt,
Count(CASE WHEN dbo.Product_Categories.category_name='desserts'
THEN dbo.Transactions.quantity END) As [desserts],
Count(CASE WHEN dbo.Product_Categories.category_name='meat'
THEN dbo.Transactions.quantity END) As [meat],
Count(CASE WHEN dbo.Product_Categories.category_name='juices'
THEN dbo.Transactions.quantity END) As [juices],
Count(CASE WHEN dbo.Product_Categories.category_name='baker products'
THEN dbo.Transactions.quantity END) As [baker products],
Count(CASE WHEN dbo.Product_Categories.category_name='canned'
THEN dbo.Transactions.quantity END) As [canned]

FROM dbo.Product_Categories
INNER JOIN dbo.Receipts
INNER JOIN dbo.PRODUCTS
INNER JOIN dbo.TRANSACTIONS ON dbo.PRODUCTS.id_product = dbo.TRANSACTIONS.id_product
ON dbo.RECEIPTS.id_receipt = dbo.TRANSACTIONS.id_receipt
ON dbo.Product_Categories.id_prod_cut = dbo.Products.id_product

GROUP BY dbo.Receipts.id_receipt ;


Related Topics



Leave a reply



Submit