Pivot Table in SQL without using Aggegate Function - sql-server

I am using SQL server 2012 . I have table like
col1 col2 col3
1 abc AA
2 xyz BB
3 def CC
I want to convert this table into
col1 col2 col3_AA col3_BB col3_CC
1 abc AA
2 xyz BB
3 def CC
please edit table format. I am not able to do

The conditional aggregation might help you
select col1, col2,
max(case when col3 = 'AA' then col3 end) col3_AA,
max(case when col3 = 'BB' then col3 end) col3_BB,
max(case when col3 = 'CC' then col3 end) col3_CC
from table
group by col1, col2
order by col1

Try This
1. Static PIVOT query.
For example, if the column "ITEM_HEAD_ID" values can only be like 1, 2 and 3, then this is what you need. According to your given data, you can use the following query:
SELECT *, (ISNULL([1], 0 ) + ISNULL([2], 0) + ISNULL([3], 0)) AS [Total]
FROM (SELECT [TRXID],
[ITEM_HEAD_ID],
[ITEM_HEAD_AMT]
FROM [Table]) AS t
PIVOT (MAX([ITEM_HEAD_AMT])
FOR [ITEM_HEAD_ID] IN ([1], [2], [3])) AS p;
Note: [Table] is the name of your table.
The result:
TRXID 1 2 3 Total
6 100.00 100.00 300.00 500.00
7 100.00 100.00 300.00 500.00

Related

Add a Total row after each week

I am searching for a way to sum columns by week.
This is the initial table data.
Date WeekNo Col1 Col2 Col3
2020/07/01 27 1 4 3
2020/07/04 27 3 3 1
2020/07/06 28 1 1 1
2020/07/11 28 1 3 8
and I want to add a row total to every end of the week like this:
Date WeekNo Col1 Col2 Col3
2020/07/01 27 1 4 3
2020/07/04 27 3 3 1
TOTAL 27 4 7 4
2020/07/06 28 1 1 1
2020/07/11 28 1 3 8
TOTAL 28 2 4 9
I tried something similar the the code below but I have multiple columns to sum.
Do you have other ideas, suggestions?
Also, grouping sets does not create a new row if there is no data for that week to sum (like 0 or NULL).
SELECT
YEAR(Date) AS OrderYear,
MONTH(Date) AS OrderMonth,
SUM(Col1) AS SumCol1
FROM tb
GROUP BY
GROUPING SETS
(
YEAR(Date), --1st grouping set
(YEAR(Date),MONTH(Date)) --2nd grouping set
)
Is this what you are after?
My solution uses the built in with rollup addition to the group by clause.
-- create sample data
declare #data table
(
[Date] Date,
WeekNo int,
Col1 int,
Col2 int,
Col3 int
);
insert into #data ([Date], WeekNo, Col1, Col2, Col3) values
('2020-07-01', 27, 1, 4, 3),
('2020-07-04', 27, 3, 3, 1),
('2020-07-06', 28, 1, 1, 1),
('2020-07-11', 28, 1, 3, 8);
-- solution
select case when grouping(d.Date) = 0
then convert(nvarchar(10), d.Date) -- type conversion so all column values have the same type
else 'TOTAL'
end as 'Date',
d.WeekNo,
sum(d.Col1) as 'Col1',
sum(d.Col2) as 'Col2',
sum(d.Col3) as 'Col3'
from #data d
group by d.WeekNo, d.Date with rollup -- "roll up" the aggregations
having grouping(d.WeekNo) = 0; -- filter out aggregation across weeks
Gives me:
Date WeekNo Col1 Col2 Col3
---------- ----------- ----------- ----------- -----------
2020-07-01 27 1 4 3
2020-07-04 27 3 3 1
TOTAL 27 4 7 4
2020-07-06 28 1 1 1
2020-07-11 28 1 3 8
TOTAL 28 2 4 9
You only need to add (DATEPART(wk, Date)) as aggregation rule after listing the other non-aggregated columns Date,Col1, Col2, Col3. Btw, you do not need a WeekNo column, since it could already be computer by use of (DATEPART(wk, Date)).
So far so good, but ordering is such a daunting task as returning null values for WeekNo column for subtotal. I used two analytic functions ( ROW_NUMBER() and FISRT_VALUE() to overcome this problem ) :
SELECT COALESCE(Date,'TOTAL') As Date,
DATEPART(wk, Date) AS WeekNo,
SUM(Col1) AS Col1,
SUM(Col2) AS Col2,
SUM(Col3) AS Col3
FROM tb
GROUP BY GROUPING SETS ( ( Date,Col1, Col2, Col3 ),
(DATEPART(wk, Date))
)
ORDER BY CASE WHEN DATEPART(wk, Date) IS NULL
THEN
ROW_NUMBER() OVER (PARTITION BY DATEPART(wk, Date)
ORDER BY COALESCE(Date,'TOTAL') )
ELSE
DATEPART(wk, Date) -
FIRST_VALUE(DATEPART(wk, Date))
OVER ( ORDER BY COALESCE(Date,'TOTAL') ) + 1
END,
DATEPART(wk, Date)
Demo

How to Sum particular values in a column in Microsoft SQL Server?

I'm kinda new to this and I have been stuck on this for a while now.
Example:
Col1 Col2 Col3
A | H | 1
A | I | 2
A | J | 3
B | J | 4
B | K | 5
C | L | 6
How can I sum 'Col3' but only for particular values. For example sum up the values in 'Col3' where the letters in 'Col1' are in the same row as 'Col3'. So A = 6 (1+2+3) and B = 9 (4+5) and C = 6
So you get this:
Col1 Col2 Col3
A | H | 6
A | I | 6
A | J | 6
B | J | 9
B | K | 9
C | L | 6
This is what I had so far:
SELECT Col1, Col2, SUM(Col3)
FROM Table1
GROUP BY Col1, Col2;
Thanks
Just to elaborate on my comment.
You can use the window function sum() over()
Example
Declare #YourTable Table ([Col1] varchar(50),[Col2] varchar(50),[Col3] int) Insert Into #YourTable Values
('A','H',1)
,('A','I',2)
,('A','J',3)
,('B','J',4)
,('B','K',5)
,('C','L',6)
Select Col1
,Col2
,Col3 = sum(Col3) over (partition by Col1)
From #YourTable
Returns
Col1 Col2 Col3
A H 6
A I 6
A J 6
B J 9
B K 9
C L 6
Just as another way you can do this way also using join and SUM (Transact-SQL)
function.
create table TestTable (Col1 varchar(5)
, Col2 varchar(5)
, Col3 int)
insert into TestTable Values
('A', 'H', 1),
('A', 'I', 2),
('A', 'J', 3),
('B', 'J', 4),
('B', 'K', 5),
('C', 'L', 6)
SELECT tblA.Col1
,tblA.Col2
,tblB.Col3
FROM (
SELECT Col1
,Col2
FROM TestTable
) tblA
INNER JOIN (
SELECT Col1
,sum(Col3) AS Col3
FROM TestTable
GROUP BY Col1
) tblB ON tblA.Col1 = tblB.Col1
Live Demo
There are a number of ways to write data aggregation queries like this. Which to use depends on what your final results need to look like. Just to go over some basics, I’ll go over several methods here.
The simplest is to use a WHERE clause:
SELECT Col1, sum(Col3)
from MyTable
where Col1 = 'A'
This will produce a single row of data:
Col1 Col3
A | 6
To produce sums for all of the distinct values in ColA, you would use GROUP BY:
SELECT Col1, sum(Col3)
from MyTable
group by Col1
This will produce three rows of data:
Col1 Col3
A | 6
B | 9
C | 6
The above samples are pretty straightforward and basic SQL examples. It is actually a bit difficult to produce the result set from your example, where you include Col2 and show the summation, because Col2 is not part of the data aggregation. Several ways to do this:
Using a subquery:
SELECT
mt.Col1
,mt.Col2
,sub.SumCol3 Col3
from MyTable mt
inner join (select
Col1
,sum(Col3) SumCol3
from MyTable
group by Col1) sub
on sub.Col1 = mt.Col1
Using a common table expression:
WITH cteSub
as (select
Col1
,sum(Col3) SumCol3
from MyTable
group by Col1)
select
mt.Col1
,mt.Col2
,cteSub.SumCol3 Col3
from MyTable mt
inner join cteSub
on ctesub.Col1 = mt.Col1
And, perhaps the most obscure and obtuse, using aggregation fucntions with partitioning:
SELECT
Col1
,Col2
,sum(Col3) over (partition by Col1) Col3
from MyTable
Thorough and complete discussions of all the above tactics (better than anything I'd write) can be found online, by searching for "SQL" plus the appropriate term (aggregation, subquery, CTE, paritioning functions). Good luck!

SQL Table to SQL Table

I have a database table in the following format (populated via .net function, empties are blank, not NULL):
A B C D
Spoons ID
38483
Date Amt Value Type
1/1/2017 2 12 Plastic
1/2/2017 4 30 Silver
1/3/2017 1 9 Wood
How can I write a stored procedure that will result in the following table?
Col1 Col2 Col3 Col4 Col5
----------------------------------------------------
Spoons 38483 1/1/2017 2 Plastic
Spoons 38483 1/2/2017 4 Silver
Spoons 38483 1/3/2017 1 Wood
Note: I am using SQL Server 2016
SELECT LEAD ( [A], 1 ) OVER (ORDER BY [ID] asc) as Col1 FROM Table1 --- (Note I added an ID clmn)
SELECT Top 1 LEAD ( [B], 2 ) OVER (ORDER BY [ID] asc) as Col2 FROM Table1
SELECT ROW_NUMBER() OVER (ORDER BY [ID] asc) AS RowNumber, * FROM Table1 WHERE RowNumber BETWEEN x AND y
Then insert all that into a final table... Simple question = simple answer. I'm just relatively new to sql so it was difficult to figure out on my own.

value comparison on sql server 2008

There is a table of 5 columns :
col1,col2,col3,col4,monthName
Something like:
col1 | col2 | col3 | col4 | monthName
----------------------------------------
4 | 5 | 55 | 8 | January
4 | 4 | 33 | 6 | February
col1 and col2 sum must be same as col4 of the last month. So i can compare it like
select * from table1 where col1+col2=col4 where monthName='February'
but it will compare all the rows wheres i want it to be month specific something like
select *
from table1
where col1+col2 = (select col4 from table1 where monthName='January')
where monthName='February'
How i do this in correct way?
Well, It is something about monthly report.
Perhaps my main problem is getting col4 from the past month(such as january).
I am trying to explain it more clearly:
Get the col1 and col2 of current month(Which is in the monthName column) and do the sum.
Get the col4 cells value from last month. In this case it is February of monthName column.
Compare the col1+col2(Current month) to col4 (Last month in monthName).
In my first example , the row number 2 is true because 4+4=8 which is getting matched with col4 value(8) of January. If col1 and col2 sum of current month match with last month's col4 data then users are good.
I can get col1 and col2 very easily:
select sum(col1+col2) as currentTotal from table1 where monthName='February'
But how i get the col4 value from last month and store it somewhere then compare to currentTotal? Every month there will be 15 rows inserted and will be compared to last month.
Not sure if this time i explained a little better!
The month naming is dubious, but with the information we have, the following should do the trick:
-- Creating a table variable as a sample for your query.
DECLARE #T TABLE (col1 INT, col2 INT, col3 INT, col4 INT, monthName VARCHAR(25))
INSERT INTO #T VALUES (4,4,55,9,'January'),(5,4,3,6,'February'), (3,3,3,6,'March')
-- Update the references to your actual table in this query.
;WITH CTE AS (SELECT *
, DATEPART(MM,monthName+' 01 2014') Mnum
FROM #T)
SELECT CA.*
FROM CTE C
CROSS APPLY
(SELECT col1, col2, col3, col4, monthName
FROM CTE B
WHERE B.Mnum-1 = C.Mnum AND (B.col1+B.col2 = C.col4)) CA
ORDER BY Mnum
What it does, is it assigns a number for the monthname, then uses that set in order of month numbers, and with CROSS APPLY selects only rows where the sum of col1 and 2 amount to the col4 of previous month number.
You can try something like the pseudo code below
select *
from table1 t1
join
(
select monthName, SUM(col1+col2-col4) as isZero
group by monthName
) as t2
on t2.monthName = t1.monthName
where t2.isZero != 0

Update to get check_order

I have a table with values,
col1 col2 col3
1 0 ABA
1 0 ABB
1 0 ABC
2 0 BBA
2 0 BBB
2 0 BBC
I am trying to update the table to see the number of repetition of col1, in this case col1 has repeated 3 times so each update to col2 incremented by 1.
Required output after the update table
col1 col2 col3
1 1 ABA
1 2 ABB
1 3 ABC
2 1 BBA
2 2 BBB
2 3 BBC
A simple row_number() -ing should work
;with TMP as (
select *, row_number() over (partition by col1 order by col3) as RowNum
from tbl
)
update TMP set col2=RowNum
Where
tbl: is your table name
partition by col1: resets the row numbering for each col1 group
order by col3: is the basis for numbering within a col1 group
Assuming you are intending col3 to be in non-descending order, this should do it:
UPDATE MyTable
SET col2=(SELECT COUNT(*)
FROM MyTable AS T2
WHERE T2.col1=T1.col1 AND T2.col3<=T1.col3)
FROM MyTable AS T1
You will get duplicates in col2, if there are duplicates in col3 for a particular col1 value.
In case you are interested, here is a pretty verbose (and more expensive execution wise) solution using a ranking function. It has the same issue (i.e., the count gets repeated) for duplicates in col1/col3, as the previous solution:
UPDATE MyTable
SET col2=(
-- In the following query, DISTINCT merges rank dups caused by col3 dups
-- SELECT TOP(1) MyRank would also work.
SELECT DISTINCT MyRank
FROM (
SELECT col3,
DENSE_RANK() OVER (PARTITION BY col1 ORDER BY col3) AS MyRank
FROM MyTable
WHERE col1=UpdatedTable.col1
) As RankTable
WHERE RankTable.col3=UpdatedTable.col3)
FROM MyTable AS UpdatedTable

Resources