Dynamic pivot in SQL server not grouping correctly - sql-server

I'm trying to build a dynamic pivot that essentially shows subscription amounts by customer by month. The dynamic part of the pivot is working correctly, but the resulting pivot has multiple non-identical lines per customer ID and I'm not sure why. Fair warning, I'm very new to this whole SQL thing so my code may be a complete mess and for that I'm sorry
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
SELECT #ColumnName= ISNULL(#ColumnName + ',','')
+ QUOTENAME([Month])
FROM (SELECT DISTINCT TOP 99.99 PERCENT [Month] FROM [Service Contract Data].[dbo].[filtered_data] ORDER BY [Month]) AS [Month]
SET #DynamicPivotQuery =
N'SELECT [Customer ID], ' + #ColumnName + '
INTO [Service Contract Data].[dbo].[Pivot_Results] FROM [Service Contract Data].[dbo].[filtered_data]
PIVOT(SUM([Service Contract Data].[dbo].[filtered_data].[Subscription Amount])
FOR [Month] IN (' + #ColumnName + ')) AS PVTTable'
EXEC sp_executesql #DynamicPivotQuery;
#DynamicPivotQuery returns
SELECT [Customer ID], [Jan 1 2013 12:00AM],[Feb 1 2013 12:00AM],[Mar 1 2013 12:00AM],[Apr 1 2013 12:00AM],[May 1 2013 12:00AM],[Jun 1 2013 12:00AM],[Jul 1 2013 12:00AM],[Aug 1 2013 12:00AM],[Sep 1 2013 12:00AM],[Oct 1 2013 12:00AM],[Nov 1 2013 12:00AM],[Dec 1 2013 12:00AM],[Jan 1 2014 12:00AM],[Feb 1 2014 12:00AM],[Mar 1 2014 12:00AM],[Apr 1 2014 12:00AM],[May 1 2014 12:00AM],[Jun 1 2014 12:00AM],[Jul 1 2014 12:00AM],[Aug 1 2014 12:00AM],[Sep 1 2014 12:00AM],[Oct 1 2014 12:00AM],[Nov 1 2014 12:00AM],[Dec 1 2014 12:00AM],[Jan 1 2015 12:00AM],[Feb 1 2015 12:00AM],[Mar 1 2015 12:00AM],[Apr 1 2015 12:00AM],[May 1 2015 12:00AM],[Jun 1 2015 12:00AM],[Jul 1 2015 12:00AM],[Aug 1 2015 12:00AM],[Sep 1 2015 12:00AM],[Oct 1 2015 12:00AM],[Nov 1 2015 12:00AM],[Dec 1 2015 12:00AM],[Jan 1 2016 12:00AM],[Feb 1 2016 12:00AM]
INTO [Service Contract Data].[dbo].[Pivot_Results] FROM [Service Contract Data].[dbo].[filtered_data]
PIVOT(SUM([Service Contract Data].[dbo].[filtered_data].[Subscription Amount])
FOR [Month] IN ([Jan 1 2013 12:00AM],[Feb 1 2013 12:00AM],[Mar 1 2013 12:00AM],[Apr 1 2013 12:00AM],[May 1 2013 12:00AM],[Jun 1 2013 12:00AM],[Jul 1 2013 12:00AM],[Aug 1 2013 12:00AM],[Sep 1 2013 12:00AM],[Oct 1 2013 12:00AM],[Nov 1 2013 12:00AM],[Dec 1 2013 12:00AM],[Jan 1 2014 12:00AM],[Feb 1 2014 12:00AM],[Mar 1 2014 12:00AM],[Apr 1 2014 12:00AM],[May 1 2014 12:00AM],[Jun 1 2014 12:00AM],[Jul 1 2014 12:00AM],[Aug 1 2014 12:00AM],[Sep 1 2014 12:00AM],[Oct 1 2014 12:00AM],[Nov 1 2014 12:00AM],[Dec 1 2014 12:00AM],[Jan 1 2015 12:00AM],[Feb 1 2015 12:00AM],[Mar 1 2015 12:00AM],[Apr 1 2015 12:00AM],[May 1 2015 12:00AM],[Jun 1 2015 12:00AM],[Jul 1 2015 12:00AM],[Aug 1 2015 12:00AM],[Sep 1 2015 12:00AM],[Oct 1 2015 12:00AM],[Nov 1 2015 12:00AM],[Dec 1 2015 12:00AM],[Jan 1 2016 12:00AM],[Feb 1 2016 12:00AM])) AS PVTTable

Related

SQL insert first of month

I've created an initial sql insert into a table, below.
spool_month spool_year spool_month_part spool_year_part curr_cnt prev_cnt cal_prcnt_dff
July 2020 7 2020 21069199 NULL 0
September 2020 9 2020 18072707 21069199 14
October 2020 10 2020 17284440 18072707 4
November 2020 11 2020 17791289 17284440 3
December 2020 12 2020 20148679 17791289 13
January 2021 1 2021 22543049 20148679 12
February 2021 2 2021 24234982 22543049 8
March 2021 3 2021 26458351 24234982 9
April 2021 4 2021 5946066 26458351 78
Can I create an insert that would only insert new data into this table at the first of the month? So, for example at first of every month insert previous months data.
Not sure where to start with this piece, so any feedback would be appreciated.
This is easily solved by using SqlAgent; if you are only using SqlExpress you won't have access to SqlAgent, in which case you will need to look at using the Windows Task Scheduler and Powershell, if that's the case here is a useful guide
Create your procedure that will perform your insert and schedule it to run daily either from a SqlAgent Job or Powershell from link above.
In your procedure, wrap your insert with
if DatePart(day,GetDate())=1
begin
...
end

Vehicle Fitment Data Merge Overlapping Years

I have a large data set of vehicle fitment information for products, each on their own row.
I am struggling to create a query to select only the minimum and maximum years for each overlapping entry.
For example, I have data such as:
fromyear toyear makename modelname submodelname wheelbase BedLength BedTypeName bodytype note1 Note2 note3 partterminologyname exppartno
2008 2012 Chevrolet Silverado 1500 LT NULL 78.00 Fleetside NULL Black NULL NULL Truck Bed Mat 37807
2010 2010 Chevrolet Silverado 1500 LT NULL 78.00 Fleetside NULL Black NULL NULL Truck Bed Mat 37807
2014 2017 Chevrolet Silverado 1500 LT NULL 78.00 Fleetside NULL Black NULL NULL Truck Bed Mat 37807
I am not concerned with keeping the data, so I've moved my focus to an UPDATE query by selecting the minimum and maximum years, but adding something like
(SELECT MIN(p2.fromyear)
FROM prod AS p2
WHERE p1.fromyear > 0
AND p2.toyear >= p1.fromyear
AND p2.fromyear < p1.fromyear
AND ISNULL(p2.makename, '') = ISNULL(p1.makename, '')
AND ISNULL(p2.modelname, '') = ISNULL(p1.modelname, '')
AND ISNULL(p2.submodelname, '') = ISNULL(p1.submodelname, '')
AND ISNULL(FLOOR(p2.wheelbase), 0) = ISNULL(FLOOR(p1.wheelbase), 0)
AND ISNULL(FLOOR(p2.BedLength), 0) = ISNULL(FLOOR(p1.BedLength), 0)
AND ISNULL(p2.BedTypeName, '') = ISNULL(p1.BedTypeName, '')
AND ISNULL(p2.bodytype, '') = ISNULL(p1.bodytype, '')
AND ISNULL(p2.note1, '') = ISNULL(p1.note1, '')
AND ISNULL(p2.Note2, '') = ISNULL(p1.Note2, '')
AND ISNULL(p2.note3, '') = ISNULL(p1.note3, '')
AND ISNULL(p2.exppartno, '') = ISNULL(p1.exppartno, '')) AS newfrom
causes the query to run for an excessive amount of time (pulling from a table with over 150k rows).
After doing an UPDATE to merge the years, I can simply remove any duplicate rows.
The desired result would return only two rows for this model, 2008-2012 and 2014-2017
My original idea was to simply select MIN(fromyear) and MAX(toyear), however this leaves me with an issue of having the invalid year of 2013 as an option.
Is there some simple way to formulate a query to handle overlapping years like this? Everything I found in my searches did not involve matching multiple columns of data.
I would suggest joining onto a date table, with a list of sequential years as follows (to cover the full range of years in the source data):
year
-----
...
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
...
So joining your source table to the date table ON (year >= fromyear AND year <= toyear), gives the following results:
year fromyear toyear vehicle_descriptor
2008 2008 2012 Chevrolet...
2009 2008 2012 Chevrolet...
2010 2008 2012 Chevrolet...
2011 2008 2012 Chevrolet...
2012 2008 2012 Chevrolet...
2010 2010 2010 Chevrolet...
2014 2014 2017 Chevrolet...
2015 2014 2017 Chevrolet...
2016 2014 2017 Chevrolet...
2017 2014 2017 Chevrolet...
Then group (or select distinct) the rows to eliminate duplicate years. (I'm using "vehicle_descriptor" as a shorthand for all the columns that uniquely identify a vehicle in your source data.)
On the deduplicated results, add a column as follows:
(year - ROW_NUMBER() OVER (PARTITION BY vehicle_descriptor ORDER BY year ASC) ) AS year_group
This produces a unique number for every year or continuous sequence of years.
year fromyear toyear veicle_descriptor row_number year_group (year - row_number)
2008 2008 2012 Chevrolet... 1 2007
2009 2008 2012 Chevrolet... 2 2007
2010 2008 2012 Chevrolet... 3 2007
2011 2008 2012 Chevrolet... 4 2007
2012 2008 2012 Chevrolet... 5 2007
2010 2010 2010 Chevrolet... (this row removed as year 2010 is a duplicate)
2014 2014 2017 Chevrolet... 6 2008
2015 2014 2017 Chevrolet... 7 2008
2016 2014 2017 Chevrolet... 8 2008
2017 2014 2017 Chevrolet... 9 2008
Finally, once you have this year_group, simply group the rows in the way you originally envisaged, by vehicle_descriptor and year_group, and select the MIN(year) and MAX(year).
The year_group value has no particular significance is not retained in the final results - it's just there to differentiate the sequences. It works because it increments every time there is a discontinuity in the year sequence (and it increments by the amount of discontinuity).
I hope I've explained that satisfactorily. I'm not at my desktop PC, so I've written it all out by hand! If there's anything unclear, or you need a code example, let me know and I'll come back to you.

Convert "12:37:37.641 UTC Tue Apr 5 2016" date format into datatime in sql server 2008

I want to convert "12:37:37.641 UTC Tue Apr 5 2016" this string into DateTime in sql server 2008. Can anyone help me to convert this.
You might try it like this:
DECLARE #d VARCHAR(100)='12:37:37.641 UTC Tue Apr 5 2016';
SELECT CONVERT(DATETIME, SUBSTRING(#d,22,1000) + ' ' + SUBSTRING(#d,1,12),109);
The result
2016-04-05 12:37:37.640

SQL 2012 Query to output to "table" column

I have prototype of SQL query (actual query is too huge to post)
SELECT Site, Risk_Time_Stamp,COMPUTER_NAME, [IP_ADDR1_TEXT],Number_of_Risks
FROM dbo.sem_computer
WHERE [dbo].[V_SEM_COMPUTER].COMPUTER_ID = SEM_COMPUTER.COMPUTER_ID
GROUP BY Site, Risk_Time_Stamp,COMPUTER_NAME, [IP_ADDR1_TEXT],Number_of_Risks
That outputs
Site Risk_Time_Stamp COMPUTER_NAME IP_ADDR1_TEXT Number_of_Risks
16K987 Aug 14, 2015 ADBF8J2 10.90.0.52 2
16K987 Aug 14, 2015 AD25N10 10.51.0.80 1
16K987 Aug 14, 2015 N20C0F8J2 10.18.0.79 1
How to create query that will output site, along with column named RISK STATISTICS that has table, i.e.
SITE RISK STATISTICS
16K987 Risk_Time_Stamp COMPUTER_NAME IP_ADDR1_TEXT Number_of_Risks
Aug 14, 2015 ADBF8J2 10.90.0.52 2
Aug 14, 2015 AD25N10 10.51.0.80 1
Aug 14, 2015 N20C0F8J2 10.18.0.79 1
#sean-lange
I'm trying to create a flat excel file to input in Tableau . Each Site will be plotted on a map and if there are any risks, a hover-over will detail these.
A Site can have zero to many risks, hence the need for column with a table value, i.e. column with array value.

Convert Date: Day Mon YYYY hh:mm AM CET

I have these dates, that I need converted to date:
Sat Nov 22 2014 01:01 AM CET
Mon Aug 18 2014 06:32 PM CEST
All the convert or cast functions I tried didn't work, maybe someone has an idea what to do?
In the end, I would need something like
YYYY-MM-DD HH:MM:SS or DD.MM.YYYY HH:MM:SS that doesn't really matter, but I would need them in the same timezone if at all possible...
Thank You for any ideas
SQL Server can convert that if you get rid of the day of the week at the beginning and the time zone at the end:
SELECT CONVERT(DATETIME, SUBSTRING('Sat Nov 22 2014 01:01 AM CET',4,LEN('Sat Nov 22 2014 01:01 AM CET')-7))
SELECT CONVERT(DATETIME, SUBSTRING('Mon Aug 18 2014 06:32 PM CEST',4,LEN('Mon Aug 18 2014 06:32 PM CEST')-7))
I'm not sure what you mean that you need them in the same time zone.

Resources