Write non-Pivot version of a query - sql-server-2005

Here is my table structure and some data:
CREATE TABLE Travel
(
ID int primary key,
Name nvarchar(25),
City nvarchar(25),
Month varchar(3)
)
INSERT INTO Travel
(ID, Name, City, Month)
VALUES
(1, 'Name1', 'Paris','Jan'),
(2, 'Name1', 'Rome','Feb'),
(3, 'Name2', 'Italy','Jan'),
(4, 'Name2', 'Rome','Feb'),
(5, 'Name3', 'Los Angeles','Jan'),
(6, 'Name3', 'New York','Feb');
Can someone please help me write out the non-Pivot version to return the 'month' columns only when there is data (Assume the database is before SQL Server 2005).
Here is a sample query but it returns NULL data columns (Apr, May)
SELECT Name,
max(CASE WHEN MONTH = 'Jan' THEN City END) Jan,
max(CASE WHEN MONTH = 'Feb' THEN City END) Feb,
max(CASE WHEN MONTH = 'Mar' THEN City END) Mar,
max(CASE WHEN MONTH = 'Apr' THEN City END) Apr,
max(CASE WHEN MONTH = 'May' THEN City END) May
FROM Travel
GROUP BY Name
NAME JAN FEB MAR APR MAY
Name1 Paris Rome (null) (null) (null)
Name2 Italy Rome (null) (null) (null)
Name3 Los Angeles New York (null) (null) (null)
Also, what would be the PIVOT version of the query, as there is no function to aggregate the column over?

You can easily do something like this:
DECLARE
#v_sql varchar(8000)
BEGIN
Set #v_sql = 'SELECT name '
If exists (select month FROM travel WHERE month='Jan')
BEGIN
Set #v_sql = #v_sql + ', max(CASE WHEN MONTH = ''Jan'' THEN City END) Jan'
End
If exists (select month FROM travel WHERE month='Feb')
BEGIN
Set #v_sql = #v_sql + ', max(CASE WHEN MONTH = ''Feb'' THEN City END) Feb'
End
If exists (select month FROM travel WHERE month='Mar')
BEGIN
Set #v_sql = #v_sql + ', max(CASE WHEN MONTH = ''Mar'' THEN City END) Mar'
End
If exists (select month FROM travel WHERE month='Apr')
BEGIN
Set #v_sql = #v_sql + ', max(CASE WHEN MONTH = ''Apr'' THEN City END) Apr'
End
If exists (select month FROM travel WHERE month='May')
BEGIN
Set #v_sql = #v_sql + ', max(CASE WHEN MONTH = ''May'' THEN City END) May'
End
Set #v_sql = #v_sql + ' FROM Travel GROUP BY name'
EXECUTE(#v_sql)
END
Output:
NAME JAN FEB
-------- ------------- -----------
Name1 Paris Rome
Name2 Italy Rome
Name3 Los Angeles New York
Don't forget to check the Fiddle demo

Related

SQL Group Count

I have a table like this
Date County Location
2020-01-01 abc west
2020-01-02 abc north
2020-02-01 xzy west
2020-02-02 xzy east
2020-02-03 xyz east
Can we group and count so it can become
County jan feb
abc 2
xyz 3
Location jan feb
west 1
north 1
west 1
east 2
Thank you
Try this as the base query and then write a pivot query based on this query result as shown in the demo link.
For your reference FROM - Using PIVOT and UNPIVOT.
Select country
, FORMAT([date], 'MMMM') as Month
, count(*) as Tot
from YourTable
group by country, FORMAT([date], 'MMMM')
Pivot query needed an aggregate function. Here is the complete query.
create table YourTable
([Date] Date
, Country varchar(20)
, Location varchar(20))
insert into YourTable values
('2020-01-01', 'abc', 'west'),
('2020-01-02', 'abc', 'north'),
('2020-02-01', 'xzy', 'west'),
('2020-02-02', 'xzy', 'east'),
('2020-02-03', 'xyz', 'east')
Select * into #temp from(
Select country
, FORMAT([date], 'MMMM') as Month
, count(*) as Tot
from YourTable
group by country, FORMAT([date], 'MMMM')
)a
--Select * from #temp
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.Month)
FROM #temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT country, ' + #cols + ' from
(
select Country
, Month
, Tot
from #temp
) x
pivot
(
max(Tot)
for Month in (' + #cols + ')
) p '
execute(#query)
Live db<>fiddle demo.
Use conditional aggregation along with grouping sets:
select county, location,
sum(case when date >= '2020-01-01' and date < '2020-02-01' then 1 end) as jan,
sum(case when date >= '2020-02-01' and date < '2020-03-01' then 1 end) as feb
from t
group by grouping sets ( (country), (location) );

Pivoting unique users for each month, each year

I'm learning about PIVOT function and I want to try it in my DB, in the table DDOT I have events (rows) made by users during X month Y year in the YYYYMM format.
id_ev iddate id_user ...
------------------------
1 201901 321
2 201902 654
3 201903 987
4 201901 321
5 201903 987
I'm basing my query on the MS Documentation and I'm not getting errors but I'm not able to fill it with the SUM of those unique events (users). In simple words I want to know how many users (unique) checked up each month (x axis) in the year (y axis). However, I'm getting NULL as result
YYYY jan feb mar
----------------------------
2019 NULL NULL NULL
I'm expecting a full table with what I mentionted before.
YYYY jan feb mar
----------------------------
2019 2 1 1
In the code I've tried with different aggregate functions but this block is the closest to a result from SQL.
CREATE TABLE ddot
(
id_ev int NOT NULL ,
iddate int NOT NULL ,
id_user int NOT NULL
);
INSERT INTO DDOT
(
[id_ev], [iddate], [id_user]
)
VALUES
(
1, 201901, 321
),
(
2, 201902, 654
),
(
3, 201903, 987
),
(
4, 201901, 321
),
(
5, 201903, 987
)
GO
SELECT *
FROM (
SELECT COUNT(DISTINCT id_user) [TOT],
DATENAME(YEAR, CAST(iddate+'01' AS DATETIME)) [YYYY], --concat iddate 01 to get full date
DATENAME(MONTH, CAST(iddate+'01' AS DATETIME)) [MMM]
FROM DDOT
GROUP BY DATENAME(YEAR, CAST(iddate+'01' AS DATETIME)),
DATENAME(MONTH, CAST(iddate+'01' AS DATETIME))
) AS DOT_COUNT
PIVOT(
SUM([TOT])
FOR MMM IN (jan, feb, mar)
) AS PVT
Ideally you should be using an actual date in the iddate column, and not a string (number?). We can workaround this using the string functions:
SELECT
CONVERT(varchar(4), LEFT(iddate, 4)) AS YYYY,
COUNT(CASE WHEN CONVERT(varchar(2), RIGHT(iddate, 2)) = '01' THEN 1 END) AS jan,
COUNT(CASE WHEN CONVERT(varchar(2), RIGHT(iddate, 2)) = '02' THEN 1 END) AS feb,
COUNT(CASE WHEN CONVERT(varchar(2), RIGHT(iddate, 2)) = '03' THEN 1 END) AS mar,
...
FROM DDOT
GROUP BY
CONVERT(varchar(4), LEFT(iddate, 4));
Note that if the iddate column already be text, then we can remove all the ugly calls to CONVERT above:
SELECT
LEFT(iddate, 4) AS YYYY,
COUNT(CASE WHEN RIGHT(iddate, 2) = '01' THEN 1 END) AS jan,
COUNT(CASE WHEN RIGHT(iddate, 2) = '02' THEN 1 END) AS feb,
COUNT(CASE WHEN RIGHT(iddate, 2) = '03' THEN 1 END) AS mar,
...
FROM DDOT
GROUP BY
LEFT(iddate, 4);

SQL Year summary starting from given month

I have the following SQL query which Display 12 months of summary report from the given date. Output shows starting from January to December for whatever the given date. I want the outcome to start from the given date's month.
If the given date is '2016-05-01' I want the output to be like this
May 16 |June 16| July 16| ........... | Jan 17 | Feb 17 | March 17 | April 17 |
How can I achieve this?
Can some one suggest?
SELECT Name,SUM(Amount) AS PremiumTot,TotType,
sum(case when month(Dates) = 1 then Tot else 0 end) Jan,
sum(case when month(Dates) = 2 then Tot else 0 end) Feb,
sum(case when month(Dates) = 3 then Tot else 0 end) March,
sum(case when month(Dates) = 4 then Tot else 0 end) April,
sum(case when month(Dates) = 5 then Tot else 0 end) May,
sum(case when month(Dates) = 6 then Tot else 0 end) June,
sum(case when month(Dates) = 7 then Tot else 0 end) July,
sum(case when month(Dates) = 8 then Tot else 0 end) Aug,
sum(case when month(Dates) = 9 then Tot else 0 end) Sep,
sum(case when month(Dates) = 10 then Tot else 0 end) Oct,
sum(case when month(Dates) = 11 then Tot else 0 end) Nov,
sum(case when month(Dates) = 12 then Tot else 0 end) Dece
FROM
(
SELECT InvoiceMasterID,Dates ,Name,CompanyCommission AS Tot ,0 AS Expences,Amount,1 as TotType
FROM CommissionView
UNION ALL
SELECT InvoiceMasterID,Dates,Name, 0 AS Tot ,-AgentCommission AS Expences,Amount,2 as TotType
FROM CommissionViewCredit
) a
WHERE Dates between #fromDates AND Datesadd(yy,1,#fromDates)
GROUP BY Name,TotType
Seems, you want to pivot data. So, use PIVOT table!
If you want to create dynamic columns from given date, use CTE (Common Table Expressions)!
--declare variables for given date range
DECLARE #startDate DATE = '2016-05-01'
DECLARE #endDate DATE = DATEADD(mm,11,#startDate)
--declare variable to store months as: [month1], [month2], [etc.]
DECLARE #Months VARCHAR(1000) = ''
--use cte to create range of dates
;WITH MyDates AS
(
SELECT #startDate AS MyDate
UNION ALL
SELECT DATEADD(mm,1,MyDate) AS MyDate
FROM MyDates
WHERE MyDate<#endDate
)
SELECT #Months = STUFF((SELECT '],[' + CONVERT(VARCHAR(7), MyDate, 121)
FROM MyDates
FOR XML PATH('')), 1, 2, '') + ']'
--PRINT #Months:
-- prints: [2016-05],[2016-06], ... ,[2017-04]
DECLARE #qry NVARCHAR(MAX) = ''
SET #qry = N'SELECT ' + #Months +
' FROM ( ' +
' SELECT CONVERT(VARCHAR(7), Dates, 121) AS MyDate, CompanyCommission AS Tot ' +
'FROM CommissionView ' +
') AS DT ' +
'PIVOT (SUM(Tot) FOR MyDate IN(' + #Months + ')) AS PT'
EXEC (#qry)
For further information, please see:
Dynamic PIVOT
Pivots with dynamic columns
CAST and CONVERT
Good luck!

MERGE, UPDATE, INSERT T-SQL Cannot INSERT value NULL

Goal: Keep a running table of student class ranks each month of the year
Haves: I have code that provides me with columns
StudentID; '+#DateTXT+'
The DateTXT is dynamic variable, returns whatever month I'm running the code in.
Needs: I'm trying to use the MERGE, UPDATE, INSERT functions to where I can run the code once and establish a table:
| StudentID | Jan |
| 56789 | 2 |
| 12345 | 7 |
Then each month I add a new month column the permanent table:
EXEC('ALTER TABLE StudentRanking
ADD ' + #DateTXT + ' smallint NOT NULL DEFAULT(999)')
| StudentID | Jan | Feb |
| 56789 | 2 | 999 |
| 12345 | 7 | 999 |
I'll run the ranking code again for February and save it into a temporary table, which I will use to merge, update, insert with the StudentRanking table:
| StudentID | Feb |
| 56789 | 3 |
(note.. student 12345 doesn't come up)
So I'd like to end up with a running list:
EXEC('
MERGE StudentRanking AS TARGET
USING ##TEMPDB2 AS SOURCE ON (TARGET.StudentID = SOURCE.StudentID)
WHEN MATCHED AND TARGET.' + #DateTXT + ' <> SOURCE.' + #DateTXT + '
THEN UPDATE SET TARGET.' + #DateTXT + ' = SOURCE.' + #DateTXT + '
WHEN NOT MATCHED BY TARGET THEN
INSERT (StudentID, ' + #Rank_TXT + ')
VALUES (SOURCE.StudentID, SOURCE.' + #Rank_TXT + ') ')
| StudentID | Jan | Feb |
| 56789 | 2 | 3 |
| 12345 | 7 |null |
Problem: Some students leave the school, thereby creating a null ranking in proceeding months (e.g. 12345 has no rank in February), so when I try to INSERT the results from a temporary table, I get this ERROR:
SQL Server Database Error: Cannot insert the value NULL into column 'Feb', table 'tempdb.dbo.##TEMPDB'; column does not allow nulls. UPDATE fails.
I could do an ISNULL(ranking,0) but I'd rather have nulls than 0's
Always open for a different, better, approach #GarethD!
I actually got it to work by doing:
EXEC('ALTER TABLE StudentRanking
ADD ' + #Date_TXT + ' smallint DEFAULT(null)')
WHEN MATCHED AND TARGET.' + #Date_TXT + ' IS NULL
THEN UPDATE SET TARGET.' + #Date_TXT + ' = SOURCE.' + #Date_TXT + '
The quick fix is make the column not nullable. It is worth pointing out though that this solution does not scale well. A more scalable approach would be to use a properly normalised table where StudentID and Month make up your primary key.
You then have something like:
CREATE TABLE dbo.StudentRanking
(
Date DATE NOT NULL,
StudentID INT NOT NULL,
Score INT NOT NULL,
CONSTRAINT PK_StudentRanking__StudentID_Date PRIMARY KEY(Date, StudentID),
);
You can then create a view on top of this to get the table in the format you wanted:
CREATE VIEW dbo.StudentRankingByYear
WITH SCHEMABINDING
AS
SELECT StudentID,
Year = DATEPART(YEAR, Date),
Jan = SUM(CASE WHEN DATEPART(MONTH, Date) = 1 THEN Score END),
Feb = SUM(CASE WHEN DATEPART(MONTH, Date) = 2 THEN Score END),
Mar = SUM(CASE WHEN DATEPART(MONTH, Date) = 3 THEN Score END),
Apr = SUM(CASE WHEN DATEPART(MONTH, Date) = 4 THEN Score END),
May = SUM(CASE WHEN DATEPART(MONTH, Date) = 5 THEN Score END),
Jun = SUM(CASE WHEN DATEPART(MONTH, Date) = 6 THEN Score END),
Jul = SUM(CASE WHEN DATEPART(MONTH, Date) = 7 THEN Score END),
Aug = SUM(CASE WHEN DATEPART(MONTH, Date) = 8 THEN Score END),
Sep = SUM(CASE WHEN DATEPART(MONTH, Date) = 9 THEN Score END),
Oct = SUM(CASE WHEN DATEPART(MONTH, Date) = 10 THEN Score END),
Nov = SUM(CASE WHEN DATEPART(MONTH, Date) = 11 THEN Score END),
Dec = SUM(CASE WHEN DATEPART(MONTH, Date) = 12 THEN Score END)
FROM dbo.StudentRanking
GROUP BY StudentID, DATEPART(YEAR, Date);
GO
You can even create an indexed view on top of this to get the table in the format you wanted (if you really needed to, but the query should perform well enough without the need for a view), the only difference is you cannot have null columns, so the missing months would have to show as 0:
CREATE VIEW dbo.StudentRankingByYear
WITH SCHEMABINDING
AS
SELECT StudentID,
Year = DATEPART(YEAR, Date),
Jan = SUM(CASE WHEN DATEPART(MONTH, Date) = 1 THEN Score ELSE 0 END),
Feb = SUM(CASE WHEN DATEPART(MONTH, Date) = 2 THEN Score ELSE 0 END),
Mar = SUM(CASE WHEN DATEPART(MONTH, Date) = 3 THEN Score ELSE 0 END),
Apr = SUM(CASE WHEN DATEPART(MONTH, Date) = 4 THEN Score ELSE 0 END),
May = SUM(CASE WHEN DATEPART(MONTH, Date) = 5 THEN Score ELSE 0 END),
Jun = SUM(CASE WHEN DATEPART(MONTH, Date) = 6 THEN Score ELSE 0 END),
Jul = SUM(CASE WHEN DATEPART(MONTH, Date) = 7 THEN Score ELSE 0 END),
Aug = SUM(CASE WHEN DATEPART(MONTH, Date) = 8 THEN Score ELSE 0 END),
Sep = SUM(CASE WHEN DATEPART(MONTH, Date) = 9 THEN Score ELSE 0 END),
Oct = SUM(CASE WHEN DATEPART(MONTH, Date) = 10 THEN Score ELSE 0 END),
Nov = SUM(CASE WHEN DATEPART(MONTH, Date) = 11 THEN Score ELSE 0 END),
Dec = SUM(CASE WHEN DATEPART(MONTH, Date) = 12 THEN Score ELSE 0 END),
Records = COUNT_BIG(*)
FROM dbo.StudentRanking
GROUP BY StudentID, DATEPART(YEAR, Date);
GO
CREATE UNIQUE CLUSTERED INDEX UQ_StudentRankingByYear__StudentID_Year
ON dbo.StudentRankingByYear (StudentID, Year);
Change your ALTER TABLE to:
EXEC('ALTER TABLE StudentRanking
ADD ' + #DateTXT + ' smallint NULL')
Assuming the down votes are because I didn't offer an alternative that was normalized, I'd recommend using PIVOT for this type of problem.
Setup:
CREATE TABLE dbo.StudentRanking
(
MonthID CHAR(3) NOT NULL,
StudentID INT NOT NULL,
Score INT NOT NULL,
CONSTRAINT PK_StudentRanking__StudentID_Date PRIMARY KEY(MonthID, StudentID),
);
INSERT INTO dbo.StudentRanking VALUES ('JAN', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('FEB', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('MAR', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('APR', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('MAY', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('JUN', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('JUL', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('AUG', 56321, 3)
INSERT INTO dbo.StudentRanking VALUES ('SEP', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('OCT', 56321, 3)
INSERT INTO dbo.StudentRanking VALUES ('NOV', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('DEC', 56321, 2)
INSERT INTO dbo.StudentRanking VALUES ('JAN', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('FEB', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('MAR', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('APR', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('MAY', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('JUN', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('JUL', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('AUG', 56821, 2)
INSERT INTO dbo.StudentRanking VALUES ('SEP', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('OCT', 56821, 2)
INSERT INTO dbo.StudentRanking VALUES ('NOV', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('DEC', 56821, 1)
INSERT INTO dbo.StudentRanking VALUES ('JAN', 56021, 3)
INSERT INTO dbo.StudentRanking VALUES ('FEB', 56021, 3)
INSERT INTO dbo.StudentRanking VALUES ('MAR', 56021, 3)
INSERT INTO dbo.StudentRanking VALUES ('APR', 56021, 3)
INSERT INTO dbo.StudentRanking VALUES ('MAY', 56021, 3)
INSERT INTO dbo.StudentRanking VALUES ('JUN', 56021, 4)
INSERT INTO dbo.StudentRanking VALUES ('JUL', 56021, 5)
Query
SELECT * FROM StudentRanking
PIVOT (SUM(Score) FOR MonthID IN (JAN, FEB, MAR, APR,
MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC)) AS PVT
Results
The SUM(SCORE) is harmless in this instance since there is never more than one record per student per month. It's just there to allow PIVOT to know what to work around.

SQL - Combine multiple rows into single row with dynamic number of columns

I'm trying to setup a query that selects multiple rows from a table and combines similar rows into a single row with multiple columns. I believe I can do this with pivot however each row won't have the same number of columns and that's where I'm running into problems. I gave an example below of what I mean.
This:
Account Period Amount
01 0001 1111
01 0002 2222
01 0003 3333
02 0001 1111
03 0001 1111
04 0001 1111
04 0002 2222
Should be come this:
Account 0001 0002 0003
01 1111 2222 3333
02 1111
03 1111
04 1111 2222
Here is my initial query that's pulling all the data together:
WITH CTE AS(
SELECT
a.Period, a.Account, SUM(a.Amount) Amount
FROM
LedgerAP a
WHERE
a.Period >= 201500
GROUP BY a.Period, a.Account
UNION
SELECT
b.Period, b.Account, SUM(b.Amount) Amount
FROM
LedgerAR b
WHERE
b.Period >= 201500
GROUP BY b.Period, b.Account
UNION
SELECT
c.Period, c.Account, SUM(c.Amount)
FROM
LedgerEx c
WHERE
c.Period >= 201500
GROUP BY c.Period, c.Account
UNION
SELECT
d.Period, d.Account, SUM(d.Amount)
FROM
LedgerMisc d
WHERE
d.Period >= 201500
GROUP BY d.Period, d.Account
)
SELECT account,
max(case when period = #Budgetyear + '01' then SUM(amount) end) Amount1,
max(case when period = #Budgetyear + '02' then SUM(amount) end) Amount2,
max(case when period = #Budgetyear + '03' then SUM(amount) end) Amount3,
max(case when period = #Budgetyear + '04' then SUM(amount) end) Amount4,
max(case when period = #Budgetyear + '05' then SUM(amount) end) Amount5,
max(case when period = #Budgetyear + '06' then SUM(amount) end) Amount6,
max(case when period = #Budgetyear + '07' then SUM(amount) end) Amount7,
max(case when period = #Budgetyear + '08' then SUM(amount) end) Amount8,
max(case when period = #Budgetyear + '09' then SUM(amount) end) Amount9,
max(case when period = #Budgetyear + '10' then SUM(amount) end) Amount10,
max(case when period = #Budgetyear + '11' then SUM(amount) end) Amount11,
max(case when period = #Budgetyear + '12' then SUM(amount) end) Amount12
FROM CTE
GROUP BY account
ORDER BY account ASC
Now how can I go about organizing this like I have shown above? Any help would be amazing!
Credit to #Bluefeet's solution here, you can build up dynamic pivot something like this:
create table table1 (Account varchar(2), Period varchar(4), Amount int)
insert into table1 values
('01', '0001', 1111),
('01', '0002', 2222),
('01', '0003', 3333),
('02', '0001', 1111),
('03', '0001', 1111),
('04', '0001', 1111),
('04', '0002', 2222);
Dynamic Query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(t.period)
FROM table1 t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Account, ' + #cols + ' from
(
select Account
, Period
, Amount
from table1
) x
pivot
(
max(amount)
for period in (' + #cols + ')
) p '
execute(#query)
GO
Result:
+---------+------+--------+--------+
| Account | 0001 | 0002 | 0003 |
+---------+------+--------+--------+
| 01 | 1111 | 2222 | 3333 |
| 02 | 1111 | (null) | (null) |
| 03 | 1111 | (null) | (null) |
| 04 | 1111 | 2222 | (null) |
+---------+------+--------+--------+
SQL Fiddle Demo
Your basic pivot:
SELECT
SUM(case Period when '0001' then Amount end) as '0001',
SUM(case Period when '0002' then Amount end) as '0002',
SUM(case Period when '0003' then Amount end) as '0003'
FROM LedgerAP
GROUP BY Account
To create that query dynamically, which is helpful if you have many values for Period:
DECLARE #SQL varchar(max) = 'SELECT '
;WITH Periods AS
(
SELECT DISTINCT Period
FROM LedgerAP
)
SELECT #SQL = #SQL +
'SUM(case Period when ''' + Period + ''' then Amount end) as ''' + Period + ''','
SET #SQL = LEFT(#SQL,LEN(#SQL) - 1) + ' FROM LedgerAP GROUP BY Account'
EXEC(#SQL)