Populating Rows Based On Ranges - sql-server
I am working on a query for the accounting department. I have a report template that provides me with Headers, Detail, Total, and other row types. Where the row type is "D," I have a range of accounts (Start_Account/End_Account). I'm trying to write a query that will bump up against general ledger data. I'd like to be able to populate each row with the appropriate heading description. Admittedly, I am stumped, short of doing it manually.
+-----------+--------------+----------+---------------+-------------+-----------+-------------------+---------------------------+
| Report_ID | Row_Sequence | Row_Type | Start_Account | End_Account | Level_Num | Reverse_Sign_Flag | Heading_Description |
+-----------+--------------+----------+---------------+-------------+-----------+-------------------+---------------------------+
| 06 | 001 | H | | | 1 | | CONSTRUCTION INCOME |
| 06 | 002 | D | 3000 | 3099 | 10 | Y | |
| 06 | 003 | D | 3801 | 3801 | 10 | Y | |
| 06 | 004 | T | 3000 | 3099 | 11 | Y | TOTAL INCOME |
| 06 | 005 | I | 3801 | 3801 | 0 | | |
| 06 | 011 | H | | | 1 | | DIRECT CONSTRUCTION COSTS |
| 06 | 012 | D | 4000 | 4001 | 10 | | |
| 06 | 013 | D | 4011 | 4031 | 10 | | |
| 06 | 014 | D | 4041 | 4041 | 10 | | |
| 06 | 015 | T | 4000 | 4099 | 11 | | TOTAL DIRECT EXPENSES |
| 06 | 016 | E | 4002 | 4002 | 0 | | |
| 06 | 017 | E | 4032 | 4032 | 0 | | |
| 06 | 018 | E | 4051 | 4051 | 0 | | |
| 06 | 019 | T | 3000 | 3099 | 12 | Y | GROSS PROFIT FROM JOBS |
| 06 | 020 | I | 3801 | 3801 | 0 | | |
| 06 | 021 | I | 4000 | 4099 | 0 | | |
| 06 | 022 | H | | | 1 | | OVERHEAD APPLIED TO JOBS |
| 06 | 023 | D | 3402 | 3402 | 10 | Y | |
| 06 | 024 | D | 3404 | 3404 | 10 | Y | |
| 06 | 025 | D | 3417 | 3417 | 10 | Y | |
| 06 | 026 | D | 5432 | 5432 | 10 | Y | |
| 06 | 027 | D | 5471 | 5471 | 10 | Y | |
| 06 | 028 | D | 5494 | 5494 | 10 | Y | |
| 06 | 029 | D | 5495 | 5495 | 10 | Y | |
| 06 | 035 | T | 3402 | 3402 | 12 | Y | ADJUST BURDEN TO ACTUAL |
+-----------+--------------+----------+---------------+-------------+-----------+-------------------+---------------------------+
As outputs, I would have:
Start_Account
End_Account
Heading_1
Heading_2
Heading_3
Using the JPG:
Level_Num 1 would correspond to Heading_1
Level_Num 11 would correspond to Heading_2
Levl_Num 12 would be Heading_3
So, for example, for Start_Account = 3000, End_Account = 3099:
Heading_1 would be "Construction Income,"
Heading_2 would be "Total Income,"
Heading_3 would be "Gross Profit From Jobs."
Now when I join to the general ledger detail, I'd like to be able to look up the proper header titles based on the start and end accounts.
It is really hard to understand what you are trying to achieve. Anyway here is a script that dynamically creates headings. You will propbably have to adjust the logic to fit your requirements, but it should be a good starting point:
declare #startAccount int = 3000
declare #endAccount int = 3099
declare #tmp table(Report_ID varchar(10),
Row_Sequence varchar(10),
Row_Type varchar(1),
Start_Account int,
End_Account int,
Level_Num int,
Reverse_Sign_Flag varchar(1),
Heading_Description varchar(max))
insert into #tmp values ('06','001','H',null,null,1 ,'','CONSTRUCTION INCOME') ,('06','002','D',3000,3099,10,'Y','') ,('06','003','D',3801,3801,10,'Y','') ,('06','004','T',3000,3099,11,'Y','TOTAL INCOME') ,('06','005','I',3801,3801,0 ,'','') ,('06','011','H',null,null,1 ,'','DIRECT CONSTRUCTION COSTS') ,('06','012','D',4000,4001,10 ,'','') ,('06','013','D',4011,4031,10 ,'','') ,('06','014','D',4041,4041,10 ,'','') ,('06','015','T',4000,4099,11 ,'','TOTAL DIRECT EXPENSES') ,('06','016','E',4002,4002,0 ,'','') ,('06','017','E',4032,4032,0 ,'','') ,('06','018','E',4051,4051,0 ,'','') ,('06','019','T',3000,3099,12,'Y','GROSS PROFIT FROM JOBS') ,('06','020','I',3801,3801,0 ,'','') ,('06','021','I',4000,4099,0 ,'','') ,('06','022','H',NULL,NULL,1 ,'','OVERHEAD APPLIED TO JOBS') ,('06','023','D',3402,3402,10 ,'Y','') ,('06','024','D',3404,3404,10 ,'Y','') ,('06','025','D',3417,3417,10 ,'Y','') ,('06','026','D',5432,5432,10 ,'Y','') ,('06','027','D',5471,5471,10 ,'Y','') ,('06','028','D',5494,5494,10 ,'Y','') ,('06','029','D',5495,5495,10 ,'Y','') ,('06','035','T',3402,3402,12 ,'Y','ADJUST BURDEN TO ACTUAL')
DECLARE #Heading_1 varchar(100)
, #Heading_2 varchar(100)
, #Heading_3 varchar(100)
, #minRowSequence varchar(10)
select #minRowSequence = min(Row_Sequence)
from #tmp
where Start_Account=#startAccount and End_Account=#endAccount
select #Heading_1 = Heading_Description
from #tmp
where isnull(Start_Account,'')=''
and isnull(End_Account,'')=''
and Level_Num=1
and Row_Sequence < #minRowSequence
select #Heading_2 = Heading_Description
from #tmp
where Start_Account=#startAccount
and End_Account=#endAccount
and Level_Num=11
select #Heading_3 = Heading_Description
from #tmp
where Start_Account=#startAccount
and End_Account=#endAccount
and Level_Num=12
DECLARE #sql nvarchar(max) = ''
set #sql = #sql + 'select ' + cast(#startAccount as varchar(max)) + ' AS Start_Account, '
set #sql = #sql + cast(#endAccount as varchar(max)) +' AS End_Account, '
set #sql = #sql + '''' + #Heading_1 + ''' AS Heading_1, '
set #sql = #sql + '''' + #Heading_2 + ''' AS Heading_2, '
set #sql = #sql + '''' + #Heading_3 + ''' AS Heading_3 '
exec(#sql)
Output:
Related
Pivoting a table with multiple columns in SQL
My goal here is to take a list of two corresponding store numbers and provide an output similar to: Ultimate goal: produce a list of closest stores by travel time and distance based on source data of 2 rows per zip9 where each row is the travel time in distance, and in time, to a store in question. The result is that each zip code has 2 stores to choose from, and the requirement is being able to return one row with both options. +-----------+---------------+---------------------+-------------------+-------------------------+ | zip | Shortest_time | Shortest_time_store | Shortest_distance | Shortest_distance_store | +-----------+---------------+---------------------+-------------------+-------------------------+ | 70011134 | 38.7035 | 75 | 21.3124 | 115 | | 70011186 | 38.4841 | 75 | 21.4144 | 115 | | 70011207 | 39.1567 | 75 | 21.1826 | 115 | | 100013232 | 22.976 | 145 | 9.5031 | 115 | | 112075140 | 21.888 | 145 | 7.3705 | 115 | +-----------+---------------+---------------------+-------------------+-------------------------+ Original dataset +---------------+--------------------------+-----------------------+------------------+ | CORRECTED_ZIP | SourceOrganizationNumber | Travel Time (Minutes) | Distance (Miles) | +---------------+--------------------------+-----------------------+------------------+ | 70011134 | 75 | 38.7035 | 26.8628 | | 70011134 | 115 | 39.3969 | 21.3124 | | 70011186 | 75 | 38.4841 | 26.7609 | | 70011186 | 115 | 39.6389 | 21.4144 | | 70011207 | 75 | 39.1567 | 31.2771 | | 70011207 | 115 | 39.188 | 21.1826 | | 100013232 | 115 | 28.6561 | 9.50311 | | 100013232 | 145 | 22.976 | 10.0307 | | 112075140 | 115 | 36.1803 | 7.37053 | | 112075140 | 145 | 21.888 | 9.50123 | +---------------+--------------------------+-----------------------+------------------+ Dataset after I've modified it with this query: SELECT TOP 1000 [corrected_zip] , TRY_CONVERT( DECIMAL(18, 4), ROUND([Travel Time (Minutes)], 4)) AS [Unit of Measurement] , [SourceOrganizationNumber] , 'Time' AS [Type] FROM [db].[dbo].[my_table_A] [tt] WHERE [tt].[CORRECTED_ZIP] IN('070011134', '070011186', '070011207', '112075140', '100013232') AND [Travel Time (Minutes)] IN ( SELECT MIN([Travel Time (Minutes)]) FROM [db].[dbo].[my_table_A] WHERE [CORRECTED_ZIP] = [tt].[CORRECTED_ZIP] GROUP BY [CORRECTED_ZIP] ) UNION ALL SELECT TOP 1000 [corrected_zip] , TRY_CONVERT( DECIMAL(18, 4), ROUND([Distance (Miles)], 4)) , [SourceOrganizationNumber] , 'Distance' FROM [db].[dbo].[my_table_A] [tt] WHERE [tt].[CORRECTED_ZIP] IN('070011134', '070011186', '070011207', '112075140', '100013232') AND [Distance (Miles)] IN ( SELECT MIN([Distance (Miles)]) FROM [db].[dbo].[my_table_A] WHERE [CORRECTED_ZIP] = [tt].[CORRECTED_ZIP] GROUP BY [CORRECTED_ZIP] ) ORDER BY [CORRECTED_ZIP]; +---------------+---------------------+--------------------------+----------+ | corrected_zip | Unit of Measurement | SourceOrganizationNumber | Type | +---------------+---------------------+--------------------------+----------+ | 70011134 | 38.7035 | 75 | Time | | 70011134 | 21.3124 | 115 | Distance | | 70011186 | 21.4144 | 115 | Distance | | 70011186 | 38.4841 | 75 | Time | | 70011207 | 39.1567 | 75 | Time | | 70011207 | 21.1826 | 115 | Distance | | 100013232 | 9.5031 | 115 | Distance | | 100013232 | 22.976 | 145 | Time | | 112075140 | 21.888 | 145 | Time | | 112075140 | 7.3705 | 115 | Distance | +---------------+---------------------+--------------------------+----------+ Data after I attempted to pivot it +---------------+--------------------------+----------+---------+ | corrected_zip | SourceOrganizationNumber | Distance | Time | +---------------+--------------------------+----------+---------+ | 070011134 | 115 | 21.3124 | NULL | | 070011134 | 75 | NULL | 38.7035 | | 070011186 | 115 | 21.4144 | NULL | | 070011186 | 75 | NULL | 38.4841 | | 070011207 | 115 | 21.1826 | NULL | | 070011207 | 75 | NULL | 39.1567 | | 100013232 | 115 | 9.5031 | NULL | | 100013232 | 145 | NULL | 22.9760 | | 112075140 | 115 | 7.3705 | NULL | | 112075140 | 145 | NULL | 21.8880 | +---------------+--------------------------+----------+---------+ It seems like my issue is picking the correct store ID as opposed to grouping by store ID?
You can use row_number() twice in a subquery(once to rank by time, another by distance), and then do conditional aggregation in the outer query: select corrected_zip, min(travel_time) shortest_time, min(case when rnt = 1 then source_organization_number end) shortest_time_store, min(distance) shortest_distance, min(case when rnd = 1 then source_organization_number end) shortest_distance_store from ( select t.*, row_number() over(partition by corrected_zip order by travel_time) rnt, row_number() over(partition by corrected_zip order by distance) rnd from mytable t ) t group by corrected_zip
How to find max(sortnumber) on item code in SQL Server?
I have following SQL Server table ITEM: +------------+-----------+------+--------+-----------+------------+ | Date | item_code | name | in/out | total_qty | SortNumber | +------------+-----------+------+--------+-----------+------------+ | 08/07/2019 | 001 | A | -50 | 100 | 8 | | 07/07/2019 | 001 | A | 50 | 100 | 7 | | 06/07/2019 | 003 | C | 25 | 25 | 6 | | 05/07/2019 | 001 | A | 50 | 50 | 5 | | 04/07/2019 | 002 | B | 100 | 200 | 4 | | 03/07/2019 | 003 | C | -25 | 0 | 3 | | 02/07/2019 | 003 | C | 25 | 25 | 2 | | 01/07/2019 | 002 | B | 100 | 100 | 1 | +------------+-----------+------+--------+-----------+------------+ I've tried: select itemcode, max(Sort_Number) from ITEM group by item_code order by item_code asc but I want result: +---------------------+-----------+------------------+ | Distinct(item_code) | Total_qty | Max(Sort_Number) | +---------------------+-----------+------------------+ | 001 | 100 | 8 | | 002 | 200 | 4 | | 003 | 25 | 6 | +---------------------+-----------+------------------+ Can anyone help me?
The below query gives you the desired result - With cteItem as ( select item_code, total_qty, SortNumber, Row_Number() over (partition by item_code order by SortNumber desc) maxSortNumber from ITEM ) select item_code, total_qty, SortNumber from cteItem where maxSortNumber = 1
just need to add max(sort_number) to your query select item_code ,max(total_qty), max(sort_number) from ITEM group by item_code order by item_code asc
T-SQL: Values are grouped by month, if there is no value for a month the month should also appear and display "NULL"
i have a SQL that displays turnover, stock and other values for stores grouped by month. Logically, if there is no value for a month, the month doesn't appear. The target is that the empty month should appear and display "NULL" for the values. The empty months should range from the #FROM to the #TO parameter (201807 to 201907) in this case. Before: +-------+--------+----------+----------+-------+ | Store | Month | Incoming | Turnover | Stock | +-------+--------+----------+----------+-------+ | 123 | 201810 | 5 | 4 | 1 | | 123 | 201811 | 0 | 1 | 0 | | 123 | 201901 | 25 | 5 | 20 | | 123 | 201902 | 5 | 10 | 15 | | 123 | 201903 | 8 | 9 | 14 | | 123 | 201904 | 5 | 4 | 15 | | 123 | 201905 | 10 | 5 | 20 | +-------+--------+----------+----------+-------+ After: +-------+--------+----------+----------+-------+ | Store | Month | Incoming | Turnover | Stock | +-------+--------+----------+----------+-------+ | 123 | 201807 | NULL | NULL | NULL | | 123 | 201808 | NULL | NULL | NULL | | 123 | 201809 | NULL | NULL | NULL | | 123 | 201810 | 5 | 4 | 1 | | 123 | 201811 | 0 | 1 | 0 | | 123 | 201812 | NULL | NULL | NULL | | 123 | 201901 | 25 | 5 | 20 | | 123 | 201902 | 5 | 10 | 15 | | 123 | 201903 | 8 | 9 | 14 | | 123 | 201904 | 5 | 4 | 15 | | 123 | 201905 | 10 | 5 | 20 | | 123 | 201906 | NULL | NULL | NULL | | 123 | 201907 | NULL | NULL | NULL | +-------+--------+----------+----------+-------+ Code Example: db<>fiddle I have absolutely no idea how to solve this and will thank you in advance for your help! :)
You can try to use cte recursive make a calendar table, then do outer-join ;WITH CTE AS ( SELECT CAST(CAST(#FROM AS VARCHAR(10)) + '01' AS DATE) fromDt, CAST(CAST(#TO AS VARCHAR(10)) + '01' AS DATE) toDt, Store FROM (SELECT DISTINCT Store FROM #Test) t1 UNION ALL SELECT DATEADD(MONTH,1,fromDt),toDt,Store FROM CTE WHERE DATEADD(MONTH,1,fromDt) <= toDt ) SELECT FORMAT(fromDt,'yyyyMM') Month, c.Store, t.Incoming, t.Turnover, t.Stock FROM CTE c LEFT JOIN #Test t on c.fromDt = CAST(CAST(t.Month AS VARCHAR(10)) + '01' AS DATE) and c.Store = t.Store sqlfiddle
Sum, Group by and Null
I'm dipping my toes into SQL. I have the following table +------+----+------+------+-------+ | Type | ID | QTY | Rate | Name | +------+----+------+------+-------+ | B | 1 | 1000 | 21 | Jack | | B | 2 | 2000 | 12 | Kevin | | B | 1 | 3000 | 24 | Jack | | B | 1 | 1000 | 23 | Jack | | B | 3 | 200 | 13 | Mary | | B | 2 | 3000 | 12 | Kevin | | B | 4 | 4000 | 44 | Chris | | B | 4 | 5000 | 43 | Chris | | B | 3 | 1000 | 26 | Mary | +------+----+------+------+-------+ I don't know how I would leverage Sum and Group by to achieve the following result. +------+----+------+------+-------+------------+ | Type | ID | QTY | Rate | Name | Sum of QTY | +------+----+------+------+-------+------------+ | B | 1 | 1000 | 21 | Jack | 5000 | | B | 1 | 3000 | 24 | Jack | Null | | B | 1 | 1000 | 23 | Jack | Null | | B | 2 | 3000 | 12 | Kevin | 5000 | | B | 2 | 3000 | 12 | Kevin | Null | | B | 3 | 200 | 13 | Mary | 1200 | | B | 3 | 1000 | 26 | Mary | Null | | B | 4 | 4000 | 44 | Chris | 9000 | | B | 4 | 5000 | 43 | Chris | Null | +------+----+------+------+-------+------------+ Any help is appreciated!
You can use window function : select t.*, (case when row_number() over (partition by type, id order by name) = 1 then sum(qty) over (partition by type, id order by name) end) as Sum_of_QTY from table t;
How to retrieve the data on a single row?
I have a table with some data, something like this: +---------+---------+---------+---------+-------------+ | Column1 | Column2 | Column3 | Column4 | Column5 | +---------+---------+---------+---------+-------------+ | 38073 | 16 | abc | 444 | 4/28/2015 | | 38076 | 70 | gug | 555 | 4/30/2015 | | 38098 | 13 | yyy | 111 | 5/12/2015 | | 38098 | 13 | yyy | 112 | 5/13/2015 | | 38098 | 13 | yyy | 113 | 5/14/2015 | | 38098 | 13 | yyy | 114 | 5/15/2015 | | 38100 | 17 | abc | 115 | 5/13/2015 | +---------+---------+---------+---------+-------------+ What I want to do is to have the values from Columns 4 and 5 on a single row, something like this : +---------+----------+-----------+----------+-----------+----------+-----------+----------+-------------+ | Col1 | Col4Val1 | Col5Val1 | Col4Val2 | Col5Val2 | Col4Val3 | Col5Val3 | Col4Val4 | Col5Val4 | +---------+----------+-----------+----------+-----------+----------+-----------+----------+-------------+ | 38073 | 444 | 4/28/2015 | null | null | null | null | null | null | | 38076 | 555 | 4/30/2015 | null | null | null | null | null | null | | 38098 | 111 | 5/12/2015 | 112 | 5/13/2015 | 113 | 5/14/2015 | 114 | 5/15/2015 | +---------+----------+-----------+----------+-----------+----------+-----------+----------+-------------+ Appreciate the help if possible. Thank you. Bogdan
You can use a UNION to unpivot the data with a CTE, then PIVOT the columns. You can achieve this dynamically too, there are hundreds of articles that will show you how to do that: ;WITH CTE AS ( SELECT [Column1], CAST([Column4] AS VARCHAR) AS [ColumnVals], 'Col4Val'+CAST(ROW_NUMBER() OVER(PARTITION BY [Column1] ORDER BY (SELECT 1)) AS VARCHAR) AS [Pivot] FROM Table1 UNION SELECT [Column1], [Column5], 'Col5Val'+CAST(ROW_NUMBER() OVER(PARTITION BY [Column1] ORDER BY (SELECT 1)) AS VARCHAR) AS [Pivot] FROM Table1) SELECT [Column1], [Col4Val1], [Col5Val1], [Col4Val2], [Col5Val2], [Col4Val3], [Col5Val3], [Col4Val4], [Col5Val4] FROM CTE PIVOT (MAX([ColumnVals]) FOR [Pivot] IN ([Col4Val1], [Col5Val1], [Col4Val2], [Col5Val2], [Col4Val3], [Col5Val3], [Col4Val4], [Col5Val4])) PIV Here's a working fiddle: http://sqlfiddle.com/#!6/e992f/1