Pivot query without knowing the number of columns needed - sql-server

I have a query that returns the following data.
ProductCode DealRef
1120 23
1120 76
1130 24
Is there a way that if a product code has more than one Deal ref then it will put this into a new column? So the current result would look something like;
ProductCode Deal1 Deal2
1120 23 76
1130 24
If this is not possible then I have an idea that could work. I would do a count on the DealRef column to find out many columns i would need to pivot to. I would then need to add another column to my initial query which will be able to add an id to each row displaying something similar to the below which I'm unsure how to do.
ProductCode DealRef id
1120 23 1
1120 76 2
1130 24 1

You cannot get the fitting number of columns, but you can get as many columns as you expect to be the maximum, most of them beeing NULL:
Paste this into an empty query window and execute. Adapt to your needs
DECLARE #tbl TABLE(ProductCode INT, DealRef INT);
INSERT INTO #tbl VALUES
(1120,23)
,(1120,76)
,(1130,24);
SELECT p.*
FROM
(
SELECT 'deal' + CAST(ROW_NUMBER() OVER(PARTITION BY tbl.ProductCode ORDER BY tbl.ProductCode) AS VARCHAR(10)) AS ColumnName
,tbl.ProductCode
,tbl.DealRef
FROM #tbl AS tbl
) AS x
PIVOT
(
MIN(DealRef) FOR ColumnName IN(deal1,deal2,deal3,deal4 /*Add as many Col-names as you could maximum need*/)
) AS p
Result is
ProductCode deal1 deal2 deal3 deal4
1120 23 76 NULL NULL
1130 24 NULL NULL NULL

Related

Grouping and counting rows by value until next row differs by more than a specified value

The query I am trying to produce is very similar to this, but instead of counting where it changes, I need to count up to the point the difference exceeds a specific value.
I have tried setting a flag where the date difference is more than 14 from the previous, but that then gives 2 records - one for when the difference is greater than 14, and 1 for the rest. As the ID can appear multiple times with different dates, I cannot then group that result.
e.g.
Data:
ID Date
1A 2020-01-01
1A 2020-01-03
2B 2020-01-05
1A 2020-02-01
Result set to be:
ID Date Count
1A 2020-01-01 2
2B 2020-01-05 1
1A 2020-02-01 1
the criteria in this case being where the difference between the dates is more than 14 days
Tried:
SELECT [ID], [Date],
case when datediff(dd,lag([Date]) over (partition by ID order by [Date]),[Date])>14
then 1 else 0 end as CaseValue
FROM Table
where [Date]>'2020-02-01'
and
declare #CountValue bigint
SELECT [ID], [Date],
#CountValue=#CountValue+case when datediff(dd,lag([Date]) over (partition by ID order by [Date]),[Date])>14
then 1 else 0 end
FROM Table
where [Date]>'2020-02-01'

SQL Server 2012 Computed column

ID Date Value Average
1 10/5/2017 15 15
2 10/6/2017 25 20
3 10/7/2017 35 25
4 10/8/2017 45 35
5 10/9/2017 55 45
6 10/10/2017 65 55
7 10/11/2017 75 65
If this is my table, I want average to be a computed column and its formula in general is average of previous 3 row's Value column.
(Ex. for 2nd row it is (25+15)/2 )
How can i do such a thing in computed column? Is there any better way to achieve this.
Thanks in advance.
i would go with a view and use avg windows function
select
id,
date,
value,
avg(value) over (order by id)
from table
Updated answer: you could use frames clause like below
Working Demo
;with cte(id,date,val)
as
(
select 1 ,'10/5/2017' , 15 UNION ALL
select 2 ,'10/6/2017' , 25 UNION ALL
select 3 ,'10/7/2017' , 35 UNION ALL
select 4 ,'10/8/2017' , 45 UNION ALL
select 5 ,'10/9/2017' , 55 UNION ALL
select 6 ,'10/10/2017', 65 UNION ALL
select 7 ,'10/11/2017', 75
)
SELECT *,avg(VAL) OVER (ORDER BY id rows between 2 PRECEDING and current row ) FROM CTE

Creating calculated fields in sql

This will seem rudimentary but I can't find a concise example online that matches up.
I have three fields; m1, m2, and m3. I need to create a column or field that is the average of them three. The calculated field would be titled employment. Would the following code be suffice?
ALTER TABLE dbo.tablename ADD Employment AS Select ((m1+m2+m3)/3)
Sample data
m1 20 20 30
m2 15 17 25
m3 60 77 13
desired result.
Name m1 m2 m3 Employment
Auto body 20 20 30 23
Auto Parts 15 17 25 19
Auto Sales 60 77 13 50
You are very close, it's called Computed Column
https://technet.microsoft.com/en-us/library/ms191250(v=sql.105).aspx
ALTER TABLE dbo.tablename ADD Employment AS ((m1+m2+m3)/3)
Update:
If you would like to force data type for a computed column, you could do the following
ALTER TABLE dbo.tablename ADD Employment AS CAST((m1+m2+m3)/3 AS Numeric (9,0))
You can check Computed Columns
CREATE TABLE t1(
col1 int,
col2 int,
col3 int,
col4 as (col1*col2*col3)/3
)
insert into t1 values(1,2,3)
select * from t1

To count rows that is NOT NULL in SSRS

I want to number some base rows in table without mixing the ordering. I have table like this:
Status ProductId
A 12
NULL 25
B 35
C 56
NULL 89
NULL 99
D 120
E 140
I want to add No column, to count Statuses which is not null with same ProductId ordering, but, don't want to count NULL rows. I want the result like this:
No Status ProductId
1 A 12
NULL 25
2 B 35
3 C 56
NULL 89
NULL 99
4 D 120
5 E 140
I work on SQL Sever 2008, SSRS. Someone can give solution in SQL side or in RDL file.
You can do this:
WITH CTE
AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY Status) AS No,
Status, ProductId
FROM table1
WHERE Status IS NOT NULL
)
SELECT
c.No,
t.Status,
t.ProductId
FROM table1 AS t
LEFT JOIN CTE AS c ON c.ProductId = t.ProductId
ORDER BY ProductId;
SQL Fiddle Demo
You can use this query directly in your report.

Removing Duplicates of two columns in a query

I have a select * query which gives lots of row and lots of columns of results. I have an issue with duplicates of one column A when given the same value of another column B that I would like to only include one of.
Basically I have a column that tells me the "name" of object and another that tells me the "number". Sometimes I have an object "name" with more than one entry for a given object "number". I only want distinct "numbers" within a "name" but I want the query to give the entire table when this is true and not just these two columns.
Name Number ColumnC ColumnD
Bob 1 93 12
Bob 2 432 546
Bob 3 443 76
This example above is fine
Name Number ColumnC ColumnD
Bob 1 93 12
Bob 2 432 546
Bill 1 443 76
Bill 2 54 1856
This example above is fine
Name Number ColumnC ColumnD
Bob 1 93 12
Bob 2 432 546
Bob 2 209 17
This example above is not fine, I only want one of the Bob 2's.
Try it if you are using SQL 2005 or above:
With ranked_records AS
(
select *,
ROW_NUMBER() OVER(Partition By name, number Order By name) [ranked]
from MyTable
)
select * from ranked_records
where ranked = 1
If you just want the Name and number, then
SELECT DISTINCT Name, Number FROM Table1
If you want to know how many of each there are, then
SELECT Name, Number, COUNT(*) FROM Table1 GROUP BY Name, Number
By using a Common Table Expression (CTE) and the ROW_NUMBER OVER PARTION syntax as follows:
WITH
CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY Name, Number ORDER BY Name, Number) AS R
FROM
dbo.ATable
)
SELECT
*
FROM
CTE
WHERE
R = 1
WITH
CTE AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY Plant, BatchNumber ORDER BY Plant, BatchNumber) AS R
FROM dbo.StatisticalReports WHERE dbo.StatisticalReports. \!"FermBatchStartTime\!" >= DATEADD(d,-90, getdate())
)
SELECT
*
FROM
CTE
WHERE
R = 1
ORDER BY dbo.StatisticalReports.Plant, dbo.StatisticalReports.FermBatchStartTime

Resources