RSS Feed!

About me

I am a business intelligence developer working at Bizware since August 2015. In this blog I will present code samples, primarilly in tsql but also findings in all other parts of the Microsoft BI-stack.


Disclaimer: All code should be considered as "as-is", i.e. badly tested and not working until extensive testing have been made by anyone reading the code. :)


Happy coding!

Archive for the ‘Business Intelligence’ Category

Calculate gregorian easter sunday fast with a table valued function in tsql

Saturday, August 16th, 2014

Hi!

I’ve seen some examples floating around the net about calculate the easter sunday day. There is a quite complex algoritm behind this, based on the equinox. I’ve stumbled upon some functions in t-sql where you have a regular scalar function to calculate this, but I didn’t find any table valued function, which is a better way when you want to create date dimensions and to check bank holidays. I used sqlsunday.com blog post about easter sunday as a starting point.

So, without further introduction, I present to you a way to get the date from a table valued function instead of a scalar function:

CREATE FUNCTION [dbo].[ufn_inltab_getGregorianEasterSunday](@year SMALLINT)
RETURNS TABLE
RETURN

    WITH
    Step1 AS( SELECT a = @year%19, b = FLOOR(1.0*@year/100), c = @year%100 ),
    Step2 AS( SELECT a,b,c,d = FLOOR(1.0*b/4), e=b%4, f=FLOOR((8.0+b)/25) FROM Step1 ),
    Step3 AS( SELECT a,b,c,d,e,g = FLOOR((1.0+ b- f)/3) FROM Step2 ),
    Step4 AS( SELECT a,d,e,h = (19*a+b-d-g+15)%30, i= FLOOR(1.0*c/4), k= @year%4 FROM Step3    ),
    Step5 AS( SELECT a,h,l = (32.0+2*e+2*i-h-k)%7 FROM Step4 ),
    Step6 AS( SELECT h,l,m = FLOOR((1.0*a+11*h+22*l)/451) FROM Step5 ),
    Step7 AS( SELECT easterSunday =
                CAST( DATEADD(dd, (h+l-7*m+114)%31,
                DATEADD(mm, FLOOR((1.0*h+l-7*m+114)/31)-1,
                DATEADD(yy, @year-2000, '2000-01-01') )
                ) AS DATE)
        FROM Step6       
        )
    SELECT easterSunday
    FROM Step7

GO

 

This function could then be used as a cross apply join to get the yearly gregorian easter sunday. The next snippet shows a test sample for every year since 1950 to 2050:

-- ================================== Year test ============================ --
-- N-table on the fly:
WITH c1(N) AS ( SELECT N FROM  ( VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10) ) AS N(N) )
,c2(N) AS (SELECT a.N FROM c1 a CROSS APPLY c1 b)
,c3(N) AS (SELECT a.N FROM c2 a CROSS APPLY c2 b)
,c4(N) AS (SELECT a.N FROM c3 a CROSS APPLY c3 b)

SELECT 
	YearTab.YearTest
	,Easter.easterSunday
FROM
	(
		SELECT TOP (100) 
			YearTest = CAST( (ROW_NUMBER() OVER (ORDER BY ( SELECT NULL) ) -1) + 1950 AS SMALLINT)
		FROM c4
	) YearTab
	CROSS APPLY [dbo].[ufn_inltab_getGregorianEasterSunday] ( YearTest ) Easter 

 

If you want to create a date dimension table with the years gregorian easter sunday, this might come in handy:

-- ================================== Day test ============================ --
-- N-table on the fly:
WITH c1(N) AS ( SELECT N FROM  ( VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10) ) AS N(N) )
,c2(N) AS (SELECT a.N FROM c1 a CROSS APPLY c1 b)
,c3(N) AS (SELECT a.N FROM c2 a CROSS APPLY c2 b)
,c4(N) AS (SELECT a.N FROM c3 a CROSS APPLY c3 b)

SELECT 
	DayTab.CalenderDate
	,DayTab.YearTest
	,Easter.easterSunday
FROM
	(
		SELECT TOP (10000) 
			CalenderDate = DATEADD(D, ROW_NUMBER() OVER (ORDER BY ( SELECT NULL) ), '2010-01-01' )
			,YearTest = YEAR( DATEADD(D, ROW_NUMBER() OVER (ORDER BY ( SELECT NULL) ), '2010-01-01' ) )
			FROM c4
	) DayTab
	CROSS APPLY [dbo].[ufn_inltab_getGregorianEasterSunday] ( YearTest ) Easter 

 

I also made a variation of the function to pinpoint if a certain date is the gregorian easter date:

CREATE FUNCTION [dbo].[ufn_inltab_findGregorianEasterSunday](@date date)
RETURNS TABLE
RETURN

    WITH
    Step1 AS( SELECT a = YEAR(@date)%19, b = FLOOR(1.0*YEAR(@date)/100), c = YEAR(@date)%100 ),
    Step2 AS( SELECT a,b,c,d = FLOOR(1.0*b/4), e=b%4, f=FLOOR((8.0+b)/25) FROM Step1 ),
    Step3 AS( SELECT a,b,c,d,e,g = FLOOR((1.0+ b- f)/3) FROM Step2 ),
    Step4 AS( SELECT a,d,e,h = (19*a+b-d-g+15)%30, i= FLOOR(1.0*c/4), k= YEAR(@date)%4 FROM Step3    ),
    Step5 AS( SELECT a,h,l = (32.0+2*e+2*i-h-k)%7 FROM Step4 ),
    Step6 AS( SELECT h,l,m = FLOOR((1.0*a+11*h+22*l)/451) FROM Step5 ),
    Step7 AS( SELECT easterSunday =
                CAST( DATEADD(dd, (h+l-7*m+114)%31,
                DATEADD(mm, FLOOR((1.0*h+l-7*m+114)/31)-1,
                DATEADD(yy, YEAR(@date)-2000, '2000-01-01') )
                ) AS DATE)
        FROM Step6       
        ),
	Step8 AS ( SELECT isEasterSunday = CASE WHEN easterSunday = @date THEN 1 ELSE 0 END FROM Step7 )
    SELECT isEasterSunday
    FROM Step8

GO

 

This will give you a zero in return for every date that isn’t a gregorian easter sunday. I have only concluded march and april here, for easier visualisation:

-- ================================== find day test ============================ --
-- N-table on the fly:
WITH c1(N) AS ( SELECT N FROM  ( VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10) ) AS N(N) )
,c2(N) AS (SELECT a.N FROM c1 a CROSS APPLY c1 b)
,c3(N) AS (SELECT a.N FROM c2 a CROSS APPLY c2 b)
,c4(N) AS (SELECT a.N FROM c3 a CROSS APPLY c3 b)

SELECT 
	DayTab.CalenderDate
	,Easter.isEasterSunday
FROM
	(
		SELECT TOP (10000) 
			CalenderDate = DATEADD(D, ROW_NUMBER() OVER (ORDER BY ( SELECT NULL) ), '2010-01-01' )
			FROM c4
	) DayTab
	CROSS APPLY [dbo].[ufn_inltab_findGregorianEasterSunday] ( CalenderDate ) Easter 
WHERE MONTH(DayTab.CalenderDate) IN (3,4)

 

Well, that’s it for today. I hope you will find it usable. I make no guarantees that this code will be correct, use it with your own precaution and test it well!

/Robin

 

 

 

SQL Everyday – beräkna bostadskostnad och nettokapital

Sunday, July 13th, 2014

Hej!

Här om dagen skapade jag en stored procedure för att räkna ut bostadskostnaden mellan en hyresrätt och bostadsrätt, då jag stod i valet och kvalet om vad jag ville köpa eller hyra lägenhet.  Det finns självklart andra överväganden som inte kan tas med i beräkningen; läge, standard, utrustning, utsikt, intresse av renovering/inredning och mycket annat. Sen kanske man inte alltid kan välja, men om man kan välja kan denna sql-procedur hjälpa dig att få en översikt om hur kostnader, men också nettokapital förändras över en längre tid. Nettokapitalet bygger på sparande i sparkonto, värdepapper och bostadsvärde och räknas även det ut i proceduren.

För att få rätt data in i proceduren och inte ge någon slags översvämning i antalet inputparametrar så har jag lagt delar av dessa variabler i två styrtabeller: bostad och scenario. Bostadstabellen bygger på förväntade kostnader, ursprungsvärderingar och insatser. Eftersom ingen vet hur börsen, räntan, inflationen och värderingar ändras över tid så kan man behöva spela upp flera scenarion, detta läggs i scenariotabellen.

Bostad

CREATE TABLE [dbo].[Bostad](
[BostadId] [int] IDENTITY(1,1) NOT NULL,
[BostadNamn] [varchar](100) NULL,
[TypAvBostad] [varchar](20) NULL,
[BostadInköpskostnad] [money] NULL,
[BostadInsats] [money] NULL,
[NettoInkomstPerMånad] [money] NULL,
[HyraEllerAvgiftPerMånad] [money] NULL,
[ÖverlåtelseAvgift] [money] NULL,
[MäklarArvodeIProcentVidFörsäljning] [money] NULL,
[AvdragIProcentVidFörsäljning] [decimal](6, 2) NULL,
[UnderhållPerMånad] [money] NULL,
[VinstavdragIProcent] [decimal](6, 2) NULL,
[AmorteringPerMånad] [money] NULL,
[SparandeSparkontoInsats] [money] NULL,
[SparandeMånadssparProcentPerNettoAllt] [money] NULL,
[AktierInsats] [money] NULL,
[AktierMånadssparProcentPerNettoAllt] [money] NULL,
[FonderInsats] [money] NULL,
[FonderMånadssparProcentPerNettoAllt] [money] NULL,
[ElperMånad] [money] NULL,
[FörsäkringperMånad] [money] NULL,
[BredbandperMånad] [money] NULL,
[TvperMånad] [money] NULL,
[MatPerMånad] [money] NULL,
[ÖvrigaUtgifterPerMånad] [money] NULL,
[RänteAvdragIProcentPerÅr] [decimal](6, 2) NULL,
CONSTRAINT [PK_Bostad] PRIMARY KEY CLUSTERED
(
[BostadId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

Scenario

CREATE TABLE [dbo].[Scenario](
[ScenarioId] [int] IDENTITY(1,1) NOT NULL,
[ScenarioKod] [varchar](10) NOT NULL,
[StartÅr] [int] NULL,
[SlutÅr] [int] NULL,
[InflationProcentPerÅr] [decimal](6, 3) NULL,
[VärdeFörändringProcentPerÅr] [decimal](6, 3) NULL,
[NettoInkomstFörändringProcentPerÅr] [decimal](6, 3) NULL,
[RänteAvdragProcentPerÅr] [decimal](6, 3) NULL,
[RäntaProcentPerÅr] [decimal](6, 3) NULL,
[AktieFörändringProcentPerÅr] [decimal](6, 3) NULL,
[FonderFörändringProcentPerÅr] [decimal](6, 3) NULL,
[SparkontoFörändringProcentPerÅr] [decimal](6, 3) NULL,
PRIMARY KEY CLUSTERED
(
[ScenarioId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]


Vi sätter in lite dummydata för att få två bostadsalternativ med en relativt hög sparkvot i bostadstabellen:

INSERT INTO [MISC].[dbo].[Bostad]
([BostadNamn]
,[TypAvBostad]
,[BostadInköpskostnad]
,[BostadInsats]
,[NettoInkomstPerMånad]
,[HyraEllerAvgiftPerMånad]
,[ÖverlåtelseAvgift]
,[MäklarArvodeIProcentVidFörsäljning]
,[AvdragIProcentVidFörsäljning]
,[UnderhållPerMånad]
,[AmorteringPerMånad]
,[SparandeSparkontoInsats]
,[SparandeMånadssparProcentPerNettoAllt]
,[AktierInsats]
,[AktierMånadssparProcentPerNettoAllt]
,[FonderInsats]
,[FonderMånadssparProcentPerNettoAllt]
,[ElperMånad]
,[FörsäkringperMånad]
,[BredbandperMånad]
,[TvperMånad]
,[MatPerMånad]
,[ÖvrigaUtgifterPerMånad])
VALUES
(
'storgatan 1, 53 kvm',--<BostadNamn, varchar(100),> -- Namnet på bostaden
'Bostadsrätt',--,<TypAvBostad, varchar(20),> -- villa, bostadsrätt, hyresrätt
1800000,--,<BostadInköpskostnad, money,> -- Inköpskostnaden för villa och bostadsrätt i lokal valuta
270000,--,<BostadInsats, money,> -- Insatsen i lokal valuta
18000,--,<NettoInkomstPerMånad, money,> -- Inkomsten efter skatteavdrag (inkl. även andra bidrag netto)
3000,--,<HyraEllerAvgiftPerMånad, money,> -- hyresrätt: månadshyra, bostadrätt: avgift, villa: schablonskatt? eller 0
1000,--,<ÖverlåtelseAvgift, money,> -- kostnad vid inflyttning: hyresrätt: avgifter till förmedlare, bostadsrätt: pant, villa: pantbrev etc
2.5,--,<MäklarArvodeIProcentVidFörsäljning, money,> -- vid brf och hyresrätt
22,--,<AvdragIProcentVidFörsäljning, decimal(6,2),> -- reavinstskatt i %
1500,--,<UnderhållPerMånad, money,> -- underhåll per månad exkl renovering. 0 för hyresrätt, ca 750-2000 för brf, 2000-5000 för villa, något lägre för radhus.
2500,--,<AmorteringPerMånad, money,> -- för brf/villa: amortering på lånet (räknas INTE som kostnad i senare skede, då amortering är ett sorts sparande)
25000,--,<SparandeSparkontoInsats, money,> -- saldo på sparkontot i början av beräkningen, behöver inte användas
60,--,<SparandeMånadssparProcentPerNettoAllt, money,> -- procent av netto som går in på sparkonto
10000,--,<AktierInsats, money,> -- saldo på ISK/KF/VP-depå i början av beräkningen (för aktier), behöver inte användas
40,--,<AktierMånadssparProcentPerNettoAllt, money,> -- procent av netto som går in på ISK/KF/VP-depå
0,--,<FonderInsats, money,> -- saldo på ISK/KF/VP-depå i början av beräkningen (för fonder), behöver inte användas
0,--,<FonderMånadssparProcentPerNettoAllt, money,> -- procent av netto som går in på ISK/KF/VP-depå (för fonder), behöver inte användas
300,--,<ElperMånad, money,> -- kostnaden för el per månad
200,--,<FörsäkringperMånad, money,> -- kostnaden för försäkringar per månad relaterade till huset, familjeförsäkring
300,--,<BredbandperMånad, money,> -- kostnaden för bredband per månad (inkluderar även hemtelefoni)
200,--,<TvperMånad, money,> -- kostnaden för tv per månad (inklusive tv-avgift)
1500,--,<MatPerMånad, money,> -- kostnaden för mat per månad
2000--,<ÖvrigaUtgifterPerMånad, money,> -- kostnaden för andra utgifter per månad
)
,
(
'villavägen 1, 150 kvm',--<BostadNamn, varchar(100),> -- Namnet på bostaden
'Villa',--,<TypAvBostad, varchar(20),> -- villa, bostadsrätt, hyresrätt
3800000,--,<BostadInköpskostnad, money,> -- Inköpskostnaden för villa och bostadsrätt i lokal valuta
670000,--,<BostadInsats, money,> -- Insatsen i lokal valuta
36000,--,<NettoInkomstPerMånad, money,> -- Inkomsten efter skatteavdrag (inkl. även andra bidrag netto)
500,--,<HyraEllerAvgiftPerMånad, money,> -- hyresrätt: månadshyra, bostadrätt: avgift, villa: schablonskatt? eller 0
100000,--,<ÖverlåtelseAvgift, money,> -- kostnad vid inflyttning: hyresrätt: avgifter till förmedlare, bostadsrätt: pant, villa: pantbrev etc
2.5,--,<MäklarArvodeIProcentVidFörsäljning, money,> -- vid brf och hyresrätt
22,--,<AvdragIProcentVidFörsäljning, decimal(6,2),> -- reavinstskatt i %
4500,--,<UnderhållPerMånad, money,> -- underhåll per månad exkl renovering. 0 för hyresrätt, ca 750-2000 för brf, 2000-5000 för villa, något lägre för radhus.
5000,--,<AmorteringPerMånad, money,> -- för brf/villa: amortering på lånet (räknas INTE som kostnad i senare skede, då amortering är ett sorts sparande)
50000,--,<SparandeSparkontoInsats, money,> -- saldo på sparkontot i början av beräkningen, behöver inte användas
50,--,<SparandeMånadssparProcentPerNettoAllt, money,> -- procent av netto som går in på sparkonto
30000,--,<AktierInsats, money,> -- saldo på ISK/KF/VP-depå i början av beräkningen (för aktier), behöver inte användas
50,--,<AktierMånadssparProcentPerNettoAllt, money,> -- procent av netto som går in på ISK/KF/VP-depå
0,--,<FonderInsats, money,> -- saldo på ISK/KF/VP-depå i början av beräkningen (för fonder), behöver inte användas
0,--,<FonderMånadssparProcentPerNettoAllt, money,> -- procent av netto som går in på ISK/KF/VP-depå (för fonder), behöver inte användas
700,--,<ElperMånad, money,> -- kostnaden för el per månad
400,--,<FörsäkringperMånad, money,> -- kostnaden för försäkringar per månad relaterade till huset, familjeförsäkring
600,--,<BredbandperMånad, money,> -- kostnaden för bredband per månad (inkluderar även hemtelefoni)
400,--,<TvperMånad, money,> -- kostnaden för tv per månad (inklusive tv-avgift)
5000,--,<MatPerMånad, money,> -- kostnaden för mat per månad
7000--,<ÖvrigaUtgifterPerMånad, money,> -- kostnaden för andra utgifter per månad
)

GO

och lite data i scenario-tabellen:

INSERT INTO [MISC].[dbo].[Scenario]
([ScenarioKod]
,[StartÅr]
,[SlutÅr]
,[InflationProcentPerÅr]
,[VärdeFörändringProcentPerÅr]
,[NettoInkomstFörändringProcentPerÅr]
,[RänteAvdragProcentPerÅr]
,[RäntaProcentPerÅr]
,[AktieFörändringProcentPerÅr]
,[FonderFörändringProcentPerÅr]
,[SparkontoFörändringProcentPerÅr])
VALUES
(
'Scenario1', --<ScenarioKod, varchar(10),> -- Namn på scenario
0, --,<StartÅr, int,> -- startår för raden
3, --,<SlutÅr, int,> -- slutår för raden
1, --,<InflationProcentPerÅr, decimal(6,3),>
4, --,<VärdeFörändringProcentPerÅr, decimal(6,3),>
2, --,<NettoInkomstFörändringProcentPerÅr, decimal(6,3),>
30, --,<RänteAvdragProcentPerÅr, decimal(6,3),>
2.5, --,<RäntaProcentPerÅr, decimal(6,3),>
5, --,<AktieFörändringProcentPerÅr, decimal(6,3),>
5, --,<FonderFörändringProcentPerÅr, decimal(6,3),>
1--,<SparkontoFörändringProcentPerÅr, decimal(6,3),>
),
(
'Scenario1', --<ScenarioKod, varchar(10),> -- Namn på scenario
4, --,<StartÅr, int,> -- startår för raden
6, --,<SlutÅr, int,> -- slutår för raden
3, --,<InflationProcentPerÅr, decimal(6,3),>
-3, --,<VärdeFörändringProcentPerÅr, decimal(6,3),>
4, --,<NettoInkomstFörändringProcentPerÅr, decimal(6,3),>
20, --,<RänteAvdragProcentPerÅr, decimal(6,3),>
5.5, --,<RäntaProcentPerÅr, decimal(6,3),>
-4, --,<AktieFörändringProcentPerÅr, decimal(6,3),>
-3, --,<FonderFörändringProcentPerÅr, decimal(6,3),>
5--,<SparkontoFörändringProcentPerÅr, decimal(6,3),>
),
(
'Scenario1', --<ScenarioKod, varchar(10),> -- Namn på scenario
7, --,<StartÅr, int,> -- startår för raden
12, --,<SlutÅr, int,> -- slutår för raden
4, --,<InflationProcentPerÅr, decimal(6,3),>
1, --,<VärdeFörändringProcentPerÅr, decimal(6,3),>
5, --,<NettoInkomstFörändringProcentPerÅr, decimal(6,3),>
10, --,<RänteAvdragProcentPerÅr, decimal(6,3),>
6.5, --,<RäntaProcentPerÅr, decimal(6,3),>
7, --,<AktieFörändringProcentPerÅr, decimal(6,3),>
6, --,<FonderFörändringProcentPerÅr, decimal(6,3),>
5--,<SparkontoFörändringProcentPerÅr, decimal(6,3),>
),
(
'Scenario1', --<ScenarioKod, varchar(10),> -- Namn på scenario
13, --,<StartÅr, int,> -- startår för raden
20, --,<SlutÅr, int,> -- slutår för raden
2.5, --,<InflationProcentPerÅr, decimal(6,3),>
3, --,<VärdeFörändringProcentPerÅr, decimal(6,3),>
4, --,<NettoInkomstFörändringProcentPerÅr, decimal(6,3),>
0, --,<RänteAvdragProcentPerÅr, decimal(6,3),>
5.5, --,<RäntaProcentPerÅr, decimal(6,3),>
7, --,<AktieFörändringProcentPerÅr, decimal(6,3),>
7, --,<FonderFörändringProcentPerÅr, decimal(6,3),>
3--,<SparkontoFörändringProcentPerÅr, decimal(6,3),>
)

GO

Stored procedure

-- =============================================
-- Author: Robin Langell		
-- Create date: 2014-06-08
-- Description:	Räknar ut bostadskostnader
-- =============================================
CREATE PROCEDURE [dbo].[usp_BostadsKostnad]
	@BostadId1 int = 1,-- första bostadid,
	@BostadId2 int = 2,-- andra bostadid,
	@PeriodAntalÅr int = 15,
	@PeriodStart date = '2014-08-01',
	@InkluderaBostadFörsäljningKostnaderOchVinsterFlagga int = 1,
	@ScenarioKod varchar(10) = 'A'
AS
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    -- Pseudokod:
    -- hämta all info från tabellen. (id)
    SELECT
      RadNr = ROW_NUMBER() OVER (ORDER BY (SELECT NULL) )
      ,[BostadId]
      ,[BostadNamn]
      ,[TypAvBostad]
      ,[BostadInköpskostnad]
      ,[BostadInsats]
      ,[NettoInkomstPerMånad]
      ,[HyraEllerAvgiftPerMånad]
      ,[ÖverlåtelseAvgift]
      ,[MäklarArvodeIProcentVidFörsäljning]
      ,[AvdragIProcentVidFörsäljning]
      ,[UnderhållPerMånad]
      ,[AmorteringPerMånad]
      ,[SparandeSparkontoInsats]
      ,[SparandeMånadssparProcentPerNettoAllt]

      ,[AktierInsats]
      ,[AktierMånadssparProcentPerNettoAllt]
      ,[FonderInsats]
      ,[FonderMånadssparProcentPerNettoAllt]
      ,[ElperMånad]
      ,[FörsäkringperMånad]
      ,[BredbandperMånad]
      ,[TvperMånad]
      ,[MatPerMånad]
      ,[ÖvrigaUtgifterPerMånad]
    INTO #Bostad_grunddata
    FROM dbo.Bostad GD
    WHERE BostadId IN (@BostadId1,@BostadId2)

    -- skapa tabell med månader från startdatum
           ;WITH
				L0   AS(SELECT 1 AS C UNION ALL SELECT 1 AS O), -- 2 rows
				L1   AS(SELECT 1 AS C FROM L0 AS A CROSS JOIN L0 AS B), -- 4 rows
				L2   AS(SELECT 1 AS C FROM L1 AS A CROSS JOIN L1 AS B), -- 16 rows
				L3   AS(SELECT 1 AS C FROM L2 AS A CROSS JOIN L2 AS B), -- 256 rows
				L4   AS(SELECT 1 AS C FROM L3 AS A CROSS JOIN L3 AS B), -- 65,536 rows
				L5   AS(SELECT 1 AS C FROM L4 AS A CROSS JOIN L4 AS B), -- 4,294,967,296 rows
				Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS N FROM L5)
			SELECT TOP (12*@PeriodAntalÅr)
				MånadsNr = N-1,
				Månad = DATEADD(MONTH, N-1, @PeriodStart),
				År = CAST( FLOOR( (N-1) / 12.00 ) AS INT),
				S.InflationProcentPerÅr,
				S.NettoInkomstFörändringProcentPerÅr,
				S.RäntaProcentPerÅr,
				S.RänteAvdragProcentPerÅr,
				S.VärdeFörändringProcentPerÅr,
				S.AktieFörändringProcentPerÅr,
				S.FonderFörändringProcentPerÅr,
				S.SparkontoFörändringProcentPerÅr
				
			INTO #Månader
			FROM Nums N
				LEFT JOIN dbo.Scenario S
					ON CAST( FLOOR( (N.N-1) / 12.00 ) AS INT) BETWEEN S.StartÅr AND S.SlutÅr
			WHERE S.ScenarioKod = @ScenarioKod
			
    DECLARE
		@bostad_i int = 1,
		@bostad_i_max int = (SELECT MAX(RadNr) FROM #Bostad_grunddata )
		
    DECLARE
       @current_BostadId as DECIMAL(38,18)
      ,@current_BostadNamn as varchar(100)
      ,@current_TypAvBostad as varchar(50)
      ,@current_BostadInköpskostnad as DECIMAL(38,18)
      ,@current_BostadInsats as DECIMAL(38,18)
      ,@current_NettoInkomstPerMånad as DECIMAL(38,18)
      ,@current_HyraEllerAvgiftPerMånad as DECIMAL(38,18)
      ,@current_ÖverlåtelseAvgift as DECIMAL(38,18)
      ,@current_MäklarArvodeIProcentVidFörsäljning as DECIMAL(38,18)
      ,@current_AvdragIProcentVidFörsäljning as DECIMAL(38,18)
      ,@current_UnderhållPerMånad as DECIMAL(38,18)
      ,@current_AmorteringPerMånad as DECIMAL(38,18)
      ,@current_SparandeSparkontoInsats as DECIMAL(38,18)
      ,@current_SparandeMånadssparProcentPerNettoAllt as DECIMAL(38,18)
      ,@current_SparandeProcentPerÅrUtv as DECIMAL(38,18)
      ,@current_AktierInsats as DECIMAL(38,18)
      ,@current_AktierMånadssparProcentPerNettoAllt as DECIMAL(38,18)
      ,@current_AktierProcentPerÅrUtv as DECIMAL(38,18)
      ,@current_FonderInsats as DECIMAL(38,18)
      ,@current_FonderMånadssparProcentPerNettoAllt as DECIMAL(38,18)
      ,@current_FonderProcentPerÅrUtv as DECIMAL(38,18)
      ,@current_ElperMånad as DECIMAL(38,18)
      ,@current_FörsäkringperMånad as DECIMAL(38,18)
      ,@current_BredbandperMånad as DECIMAL(38,18)
      ,@current_TvperMånad as DECIMAL(38,18)
      ,@current_MatPerMånad as DECIMAL(38,18)
      ,@current_ÖvrigaUtgifterPerMånad as DECIMAL(38,18)
      ,@current_Lån as DECIMAL(38,18) = -1
      ,@current_BelåningsgradIProcent as DECIMAL(20,17) = NULL
      ,@current_BostadsVärde as DECIMAL(38,18) = NULL
      ,@current_RänteKostnad as DECIMAL(38,18) = NULL
      ,@current_RänteProcent as DECIMAL(38,18) = NULL
      ,@current_NettoInkomstFörändringProcentPerÅr AS DECIMAL(38,18)
      ,@current_RänteAvdragProcentPerÅr as DECIMAL(38,18)
      ,@current_värdeFörändringProcentPerÅr as DECIMAL(38,18)
      ,@current_InflationIProcentPerÅr as DECIMAL(38,18)
    
    CREATE TABLE #BoOchSparBudget
		(
			ID INT,
			ScenarioKod varchar(10),
			Datum date,
			Lägenhetsnamn varchar(100),
			TypAvBostad varchar(50),
			Månad_Inkomst money,
			-- Månadsrelaterad info:
			Månad_TotalKostnad money,
			Månad_Räntekostnad money,
			Månad_AktuellSkuld money,
			Månad_Bostadsvärde money,
			Månad_Amortering money,
			Månad_Belåningsgrad decimal(12,8),
			Månad_ÖvrigaUtgifterUnderMånad money,
			Månad_SparkvotAvNettoInkomst money,
			-- Ack:
			Ackumulerad_Kostnad money,
			Ackumulerad_RänteKostnad money,
			Ackumulerad_Amortering money,
			Ackumulerad_AktieKonto money,
			Ackumulerad_FonderKonto money,
			Ackumulerad_SparKonto money,
			NettoSkuldsättning money,
			FörsäljningsKostnader money
		)
    
    CREATE TABLE #Månadskostnader
		(
					current_Månad date,
					current_InflationIProcentPerÅr decimal(38,18),
					current_Lån decimal(38,18),
					current_BostadsVärde decimal(38,18),
					current_BelåningsgradIProcent decimal(38,18),
					current_RänteProcent decimal(38,18),
					current_RänteKostnad decimal(38,18),
					current_ÖvrigKostnad decimal(38,18)
		)
    
    -- loopa per bostadId   
    WHILE (@bostad_i <= @bostad_i_max )
		BEGIN
			
			SELECT
			   @current_BostadId								= BostadId
			  ,@current_BostadNamn								= BostadNamn
			  ,@current_TypAvBostad								= TypAvBostad
			  ,@current_BostadInköpskostnad						= BostadInköpskostnad
			  ,@current_BostadInsats							= BostadInsats
			  ,@current_NettoInkomstPerMånad					= NettoInkomstPerMånad
			  ,@current_HyraEllerAvgiftPerMånad					= HyraEllerAvgiftPerMånad
			  ,@current_ÖverlåtelseAvgift						= ÖverlåtelseAvgift
			  ,@current_MäklarArvodeIProcentVidFörsäljning		= MäklarArvodeIProcentVidFörsäljning
			  ,@current_AvdragIProcentVidFörsäljning			= AvdragIProcentVidFörsäljning
			  ,@current_UnderhållPerMånad						= UnderhållPerMånad
			  ,@current_AmorteringPerMånad						= AmorteringPerMånad
			  ,@current_SparandeSparkontoInsats					= SparandeSparkontoInsats
			  ,@current_SparandeMånadssparProcentPerNettoAllt   = SparandeMånadssparProcentPerNettoAllt
			  ,@current_AktierInsats							= AktierInsats
			  ,@current_AktierMånadssparProcentPerNettoAllt		= AktierMånadssparProcentPerNettoAllt
			  ,@current_FonderInsats							= FonderInsats
			  ,@current_FonderMånadssparProcentPerNettoAllt		= FonderMånadssparProcentPerNettoAllt
			  ,@current_ElperMånad								= ElperMånad
			  ,@current_FörsäkringperMånad						= FörsäkringperMånad
			  ,@current_BredbandperMånad						= BredbandperMånad
			  ,@current_TvperMånad								= TvperMånad
			  ,@current_MatPerMånad								= MatPerMånad
			  ,@current_ÖvrigaUtgifterPerMånad					= ÖvrigaUtgifterPerMånad	
			  ,@current_BostadsVärde							= @current_BostadInköpskostnad
			FROM #Bostad_grunddata
			WHERE RadNr = @bostad_i

			-- loopa per månad
				-- ackumulera
				-- summera			
			DECLARE
				@månad_i int = 1
				,@månad_i_max int = (SELECT MAX(MånadsNr) FROM #Månader )
				,@current_Månad date = (SELECT MIN(Månad) FROM #Månader )
				-- börjar alltid på år 0:
				,@current_År int = 0
				,@årFörändringFlagga bit = 0
				,@Current_NettoSparande money = 0
				,@Current_Ackumulerad_Kostnad money = 0
				,@Current_Ackumulerad_RänteKostnad money = 0
				,@Current_Ackumulerad_Amortering money = 0
				,@Current_Försäljningskostnad money = 0
				
			WHILE (@månad_i <= @månad_i_max)
				BEGIN
					
					-- hämta månader, kolla om år har ändrats:
					SELECT
						@current_Månad = Månad,
						@current_År = År,
						@årFörändringFlagga = CASE WHEN @current_År = År THEN 1 ELSE 1 END,
						@current_InflationIProcentPerÅr	= M.InflationProcentPerÅr,
						@current_NettoInkomstFörändringProcentPerÅr = M.NettoInkomstFörändringProcentPerÅr,
						@current_RänteProcent = RäntaProcentPerÅr,
						@current_RänteAvdragProcentPerÅr = RänteAvdragProcentPerÅr,
						@current_värdeförändringProcentPerÅr = M.VärdeFörändringProcentPerÅr,
						@current_AktierProcentPerÅrUtv = M.AktieFörändringProcentPerÅr,
						@current_FonderProcentPerÅrUtv = M.FonderFörändringProcentPerÅr,
						@current_SparandeProcentPerÅrUtv = M.SparkontoFörändringProcentPerÅr
					FROM #Månader M
					WHERE @månad_i = MånadsNr
				
					
				SELECT
					-- räkna ut nettolönen (ny varje år):	
					@current_NettoInkomstPerMånad = CASE 
														WHEN @månad_i % 12 = 1 THEN @current_NettoInkomstPerMånad * (1 + (@current_NettoInkomstFörändringProcentPerÅr/100.00) ) 
														ELSE @current_NettoInkomstPerMånad
													END,
					-- Följer inflationen:
					@current_HyraEllerAvgiftPerMånad *= (1 + ( (@current_InflationIProcentPerÅr/12.00) /100.00) ) ,
					@current_ElperMånad *= (1 + ( (@current_InflationIProcentPerÅr/12.00) /100.00) ),
					@current_FörsäkringperMånad *= (1 + ( (@current_InflationIProcentPerÅr/12.00) /100.00) ),
					@current_BredbandperMånad *= (1 + ( (@current_InflationIProcentPerÅr/12.00) /100.00) ), 
					@current_TvperMånad *= (1 + ( (@current_InflationIProcentPerÅr/12.00) /100.00) ), 
					@current_MatPerMånad *= (1 + ( (@current_InflationIProcentPerÅr/12.00) /100.00) ), 
					@current_ÖvrigaUtgifterPerMånad	*= (1 + ( (@current_InflationIProcentPerÅr/12.00) /100.00) )
													

/* **************************************************** */
-- Övriga månadsutgifter:
/* **************************************************** */

						SELECT 
							@Current_NettoSparande = @current_NettoInkomstPerMånad - 
														( @current_HyraEllerAvgiftPerMånad + @current_ElperMånad + @current_FörsäkringperMånad + @current_BredbandperMånad + @current_TvperMånad + @current_MatPerMånad + @current_ÖvrigaUtgifterPerMånad )
														-
														CASE 
															WHEN @månad_i = 1 THEN @current_ÖverlåtelseAvgift
															ELSE 0
														END
					

						SELECT @Current_Ackumulerad_Kostnad += 
														( @current_HyraEllerAvgiftPerMånad + @current_ElperMånad + @current_FörsäkringperMånad + @current_BredbandperMånad + @current_TvperMånad + @current_MatPerMånad + @current_ÖvrigaUtgifterPerMånad )
														+
														CASE 
															WHEN @månad_i = 1 THEN @current_ÖverlåtelseAvgift
															ELSE 0
														END	

/* **************************************************** */
-- Sparande:
/* **************************************************** */

						SELECT
							@current_AktierInsats = ( @current_AktierInsats + ( (@current_AktierMånadssparProcentPerNettoAllt / 100.00) * @Current_NettoSparande ) ) * (1 + ( (@current_AktierProcentPerÅrUtv/100.00) / 12.00) ),
							@current_FonderInsats = ( @current_FonderInsats + ( (@current_FonderMånadssparProcentPerNettoAllt / 100.00) * @Current_NettoSparande ) ) * (1 + ( (@current_FonderProcentPerÅrUtv/100.00) / 12.00) ),
							@current_SparandeSparkontoInsats = ( @current_SparandeSparkontoInsats + ( (@current_SparandeMånadssparProcentPerNettoAllt / 100.00) * @Current_NettoSparande ) ) * (1 + ( (@current_SparandeProcentPerÅrUtv/100.00) / 12.00) )
						
	
					-- Vid hyresrätt:
				IF(@current_TypAvBostad = 'Hyresrätt')
					BEGIN
					
						INSERT INTO #BoOchSparBudget
						(
							ID,
							Datum ,
							Lägenhetsnamn ,
							TypAvBostad ,
							-- Månadsrelaterad info:
							Månad_TotalKostnad ,
							Månad_Räntekostnad ,
							Månad_AktuellSkuld ,
							Månad_Bostadsvärde ,
							Månad_Amortering ,
							Månad_Belåningsgrad ,
							Månad_ÖvrigaUtgifterUnderMånad ,
							Månad_SparkvotAvNettoInkomst ,
							-- Ack:
							Ackumulerad_Kostnad ,
							Ackumulerad_RänteKostnad ,
							Ackumulerad_Amortering ,
							Ackumulerad_AktieKonto ,
							Ackumulerad_FonderKonto ,
							Ackumulerad_SparKonto ,
							NettoSkuldsättning ,
							Månad_Inkomst,
							ScenarioKod,
							FörsäljningsKostnader
						)
						SELECT 	
							@bostad_i,				
							@current_Månad,
							@current_BostadNamn,
							@current_TypAvBostad,
							Månad_TotalKostnad = 
												@current_HyraEllerAvgiftPerMånad + @current_ElperMånad + @current_FörsäkringperMånad + @current_BredbandperMånad + @current_TvperMånad + @current_MatPerMånad + @current_ÖvrigaUtgifterPerMånad
												+
												CASE 
													WHEN @månad_i = 1 THEN @current_ÖverlåtelseAvgift
													ELSE 0
												END
												,
							Månad_Räntekostnad = NULL,
							Månad_AktuellSkuld = NULL,
							Månad_Bostadsvärde = NULL,
							Månad_amortering = NULL,
							Månad_belåningsgrad = NULL,
							Månad_ÖvrigaUtgifterUnderMånad = @current_ElperMånad + @current_FörsäkringperMånad + @current_BredbandperMånad + @current_TvperMånad + @current_MatPerMånad + @current_ÖvrigaUtgifterPerMånad,
							Månad_SparkvotAvNettoInkomst = @Current_NettoSparande / @current_NettoInkomstPerMånad,
							-- Ack:
							Ackumulerad_kostnad = @Current_Ackumulerad_Kostnad,
							Ackumulerad_RänteKostnad = NULL,
							Ackumulerad_Amortering = NULL,
							Ackumulerad_AktieKonto = @current_AktierInsats,
							Ackumulerad_FonderKonto = @current_FonderInsats,
							Ackumulerad_SparKonto = @current_SparandeSparkontoInsats,
							NettoSkuld = ISNULL(@current_Lån, 0) - (@current_AktierInsats + @current_FonderInsats + @current_SparandeSparkontoInsats),
							NettoInkomstPerMånad = @current_NettoInkomstPerMånad,
							@ScenarioKod,
							FörsäljningsKostnader = 0
					END
			ELSE IF (@current_TypAvBostad IN ( 'Bostadsrätt', 'Villa', 'Radhus') )
				BEGIN

				
			--	/* **************************************************** */
			--	-- Bostadsrelaterade månadsutgifter:
			--	/* **************************************************** */

				SELECT
					-- räkna ut skulden efter amortering:
					@current_Lån =
						CASE 
							WHEN @månad_i = 1 AND @current_BostadInköpskostnad > 0 THEN @current_BostadInköpskostnad - @current_BostadInsats
							WHEN @current_Lån >= 0 THEN @current_Lån - @current_AmorteringPerMånad
						END


				SELECT 
				-- räkna ut bostadsvärdet:
					@current_BostadsVärde *= (1+((@current_värdeförändringProcentPerÅr/100.00)/12.00))
					--@current_BostadsVärde = @current_BostadsVärde 
										
				SELECT 
					-- räkna ut belåningsgraden:
					@current_BelåningsgradIProcent = @current_Lån / @current_BostadsVärde
				
				SELECT 
					-- räkna ut månadsräntekostnaden på lånet:
					@current_RänteKostnad = @current_Lån * ((@current_RänteProcent/100.00)/12.00) * (1-(@current_RänteAvdragProcentPerÅr/100.00) )

					-- Ackumulerade värden:
				SELECT
					@Current_Ackumulerad_RänteKostnad =  ISNULL(@Current_Ackumulerad_RänteKostnad, 0) + @current_RänteKostnad,
					@Current_Ackumulerad_Kostnad += 
														( @current_HyraEllerAvgiftPerMånad + @current_ElperMånad + @current_FörsäkringperMånad + @current_BredbandperMånad + @current_TvperMånad + @current_MatPerMånad + @current_ÖvrigaUtgifterPerMånad )
														+
														ISNULL(@current_RänteKostnad, 0 )
														+
														CASE 
															WHEN @månad_i = 1 THEN @current_ÖverlåtelseAvgift
															ELSE 0
														END	,
					@Current_Ackumulerad_Amortering += @current_AmorteringPerMånad,
					@Current_Försäljningskostnad = 
													CASE 
														WHEN @månad_i = @månad_i_max AND @InkluderaBostadFörsäljningKostnaderOchVinsterFlagga = 1 
															THEN 
																-- om vinst vid försäljning:
																CASE
																	WHEN @current_BostadsVärde > @current_BostadInköpskostnad THEN
																			(@current_BostadsVärde - @current_BostadInköpskostnad) 
																			* (@current_AvdragIProcentVidFörsäljning/100.00)
																	ELSE 0
																END +
																@current_BostadsVärde * (@current_MäklarArvodeIProcentVidFörsäljning/100.00)
														ELSE 0
													END														
/* ********************************** */
-- #BoOchSparBudget
/* ********************************** */

						INSERT INTO #BoOchSparBudget
						(
							ID,
							Datum ,
							Lägenhetsnamn ,
							TypAvBostad ,
							-- Månadsrelaterad info:
							Månad_TotalKostnad ,
							Månad_Räntekostnad ,
							Månad_AktuellSkuld ,
							Månad_Bostadsvärde ,
							Månad_Amortering ,
							Månad_Belåningsgrad ,
							Månad_ÖvrigaUtgifterUnderMånad ,
							Månad_SparkvotAvNettoInkomst ,
							-- Ack:
							Ackumulerad_Kostnad ,
							Ackumulerad_RänteKostnad ,
							Ackumulerad_Amortering ,
							Ackumulerad_AktieKonto ,
							Ackumulerad_FonderKonto ,
							Ackumulerad_SparKonto ,
							NettoSkuldsättning ,
							Månad_Inkomst,
							ScenarioKod,
							FörsäljningsKostnader
						)
						SELECT 	
							@bostad_i,
							@current_Månad,
							@current_BostadNamn,
							@current_TypAvBostad,
							Månad_TotalKostnad = 
												@current_HyraEllerAvgiftPerMånad + @current_ElperMånad + @current_FörsäkringperMånad + @current_BredbandperMånad + @current_TvperMånad + @current_MatPerMånad + @current_ÖvrigaUtgifterPerMånad
												+
												ISNULL(@current_RänteKostnad, 0)
												+
												CASE 
													WHEN @månad_i = 1 THEN @current_ÖverlåtelseAvgift
													ELSE 0
												END
												+
												@Current_Försäljningskostnad
												,
							Månad_Räntekostnad = @current_RänteKostnad,
							Månad_AktuellSkuld = @current_Lån,
							Månad_Bostadsvärde = @current_BostadsVärde,
							Månad_amortering   = @current_AmorteringPerMånad,
							Månad_belåningsgrad = @current_BelåningsgradIProcent,
							Månad_ÖvrigaUtgifterUnderMånad = @current_ElperMånad + @current_FörsäkringperMånad + @current_BredbandperMånad + @current_TvperMånad + @current_MatPerMånad + @current_ÖvrigaUtgifterPerMånad,
							Månad_SparkvotAvNettoInkomst = @Current_NettoSparande / @current_NettoInkomstPerMånad,
							-- Ack:
							Ackumulerad_kostnad = @Current_Ackumulerad_Kostnad + @Current_Försäljningskostnad,
							Ackumulerad_RänteKostnad = @Current_Ackumulerad_RänteKostnad,
							Ackumulerad_Amortering = @Current_Ackumulerad_Amortering,
							Ackumulerad_AktieKonto = @current_AktierInsats,
							Ackumulerad_FonderKonto = @current_FonderInsats,
							Ackumulerad_SparKonto = @current_SparandeSparkontoInsats,
							NettoSkuld = ISNULL(@current_Lån, 0) - (@current_AktierInsats + @current_FonderInsats + @current_SparandeSparkontoInsats) 
							-- Räkna med värdet på bostaden efter lånet räknats bort:
							- (@current_BostadsVärde-@current_Lån)
							+ @Current_Försäljningskostnad
							,
							NettoInkomstPerMånad = @current_NettoInkomstPerMånad,
							@ScenarioKod,
							FörsäljningsKostnader = @Current_Försäljningskostnad

						
			END
				
				
					SET @månad_i = (@månad_i + 1)
					SET @årFörändringFlagga = 0
				END
		
			SET @bostad_i = (@bostad_i + 1)
		
		-- 0 på den bostad vi nyss har kört igenom:
		SELECT
			  @current_BostadInköpskostnad						= NULL
			  ,@current_BostadInsats							= NULL
			  ,@current_NettoInkomstPerMånad					= NULL
			  ,@current_InflationIProcentPerÅr					= NULL
			  ,@current_HyraEllerAvgiftPerMånad					= NULL
			  ,@current_ÖverlåtelseAvgift						= NULL
			  ,@current_MäklarArvodeIProcentVidFörsäljning		= NULL
			  ,@current_AvdragIProcentVidFörsäljning			= NULL
			  ,@current_UnderhållPerMånad						= NULL
			  ,@current_AmorteringPerMånad						= NULL
			  ,@current_SparandeSparkontoInsats					= NULL
			  ,@current_SparandeMånadssparProcentPerNettoAllt   = NULL
			  ,@current_SparandeProcentPerÅrUtv					= NULL
			  ,@current_AktierInsats							= NULL
			  ,@current_AktierMånadssparProcentPerNettoAllt		= NULL
			  ,@current_AktierProcentPerÅrUtv					= NULL
			  ,@current_FonderInsats							= NULL
			  ,@current_FonderMånadssparProcentPerNettoAllt		= NULL
			  ,@current_FonderProcentPerÅrUtv					= NULL
			  ,@current_ElperMånad								= NULL
			  ,@current_FörsäkringperMånad						= NULL
			  ,@current_BredbandperMånad						= NULL
			  ,@current_TvperMånad								= NULL
			  ,@current_MatPerMånad								= NULL
			  ,@current_ÖvrigaUtgifterPerMånad					= NULL	
			  ,@current_Lån										= NULL
			  ,@current_InflationIProcentPerÅr					= NULL
			  ,@current_BostadsVärde							= NULL
			  ,@current_BelåningsgradIProcent					= NULL
			  ,@current_RänteProcent							= NULL
			  ,@current_RänteKostnad							= NULL
			  ,@Current_NettoSparande							= 0
			  ,@Current_Ackumulerad_Kostnad						= 0
			  ,@Current_Ackumulerad_RänteKostnad				= 0
			  ,@Current_Ackumulerad_Amortering					= 0	
			  ,@current_Lån										= 0		
			  ,@Current_Försäljningskostnad						= 0  	  			
		
		END
		
	-- resultat
	SELECT
		Alt1.ScenarioKod,
		Alt1.Datum,
		Alt1_Månad_Inkomst = Alt1.Månad_Inkomst,
		Alt2_Månad_Inkomst = Alt2.Månad_Inkomst,
		Alt1_Lägenhetsnamn = Alt1.Lägenhetsnamn,
		Alt1_TypAvBostad = Alt1.TypAvBostad,
		Alt2_Lägenhetsnamn = Alt2.Lägenhetsnamn,
		Alt2_TypAvBostad = Alt2.TypAvBostad,
		Alt1_Månad_Bostadsvärde = Alt1.Månad_Bostadsvärde,
		Alt2_Månad_Bostadsvärde = Alt2.Månad_Bostadsvärde,
		Alt1_Månad_TotalKostnad = Alt1.Månad_TotalKostnad,
		Alt2_Månad_TotalKostnad = Alt2.Månad_TotalKostnad,
		Alt1_Månad_AktuellSkuld = Alt1.Månad_AktuellSkuld,
		Alt2_Månad_AktuellSkuld = Alt2.Månad_AktuellSkuld,
		Alt1_Månad_Amortering = Alt1.Månad_Amortering,
		Alt2_Månad_Amortering = Alt2.Månad_Amortering,
		Alt1_Månad_Räntekostnad = Alt1.Månad_Räntekostnad,
		Alt2_Månad_Räntekostnad = Alt2.Månad_Räntekostnad,		
		Alt1_Månad_ÖvrigaUtgifterUnderMånad = Alt1.Månad_ÖvrigaUtgifterUnderMånad,
		Alt2_Månad_ÖvrigaUtgifterUnderMånad = Alt2.Månad_ÖvrigaUtgifterUnderMånad,
		Alt1_Månad_Belåningsgrad = Alt1.Månad_Belåningsgrad,
		Alt2_Månad_Belåningsgrad = Alt2.Månad_Belåningsgrad,
		Alt1_månad_sparkvotavNettoInkomst =	Alt1.månad_sparkvotavNettoInkomst,
		Alt2_månad_sparkvotavNettoInkomst = Alt2.månad_sparkvotavNettoInkomst,
		Alt1_NettoSkuldsättning = Alt1.NettoSkuldsättning,
		Alt2_NettoSkuldsättning = Alt2.NettoSkuldsättning,
		Alt1_FörsäljningsKostnader = Alt1.FörsäljningsKostnader,
		Alt2_FörsäljningsKostnader = Alt2.FörsäljningsKostnader,
		-- ACKUMULERADE VÄRDEN:
		Alt1_Ackumulerad_Kostnad = Alt1.Ackumulerad_Kostnad,
		Alt2_ackumulerad_kostnad = Alt2.ackumulerad_kostnad,
		Alt1_Ackumulerad_RänteKostnad = Alt1.Ackumulerad_RänteKostnad,
		Alt2_Ackumulerad_RänteKostnad = Alt2.Ackumulerad_RänteKostnad,
		alt1_Ackumulerad_Amortering = alt1.Ackumulerad_Amortering,
		Alt2_Ackumulerad_Amortering = Alt2.Ackumulerad_Amortering,
		Alt1_Ackumulerad_AktieKonto = Alt1.Ackumulerad_AktieKonto,
		Alt2_Ackumulerad_AktieKonto = Alt2.Ackumulerad_AktieKonto,
		Alt1_Ackumulerad_FonderKonto = Alt1.Ackumulerad_FonderKonto,
		Alt2_Ackumulerad_FonderKonto = Alt2.Ackumulerad_FonderKonto,
		Alt1_Ackumulerad_SparKonto = Alt1.Ackumulerad_SparKonto,
		Alt2_Ackumulerad_SparKonto = Alt2.Ackumulerad_SparKonto
	FROM #BoOchSparBudget Alt1
		JOIN #BoOchSparBudget Alt2 ON Alt1.ID + 1 = Alt2.ID AND Alt1.Datum = Alt2.Datum
    
END

GO

 

För att testa koden så kör du exempelvis detta anrop:

EXEC [dbo].[usp_BostadsKostnad]
	@BostadId1 = 1,-- första bostadid,
	@BostadId2 = 2,-- andra bostadid,
	@PeriodAntalÅr = 15, -- antal år
	@PeriodStart = '2014-08-01', -- när startar jämförelsen
	@InkluderaBostadFörsäljningKostnaderOchVinsterFlagga = 1, -- inkludera mäklararvode och reavinstskatt som kostnader (vilket det är!)
	@ScenarioKod = 'Scenario1' -- vilket framtidsscenario ska användas?

 

Vi får då ett resultat där vi kan utläsa bostadsvärde, nettokapital, kostnader, amorteringar och sparande. Det finns såklart många aber med denna kod. Just nu finns exempelvis ingen förmögenhetsskatt eller någon ordentlig fastighetsskatt. Amorteringen är rak, vilket inte alla kör med. Man kan heller inte välja amorteringsfritt över en övergående period.

 

 

 

 

 

Skapa en datumdimension för ett data warehouse (inkluderar skript)

Monday, May 9th, 2011

Hej!

Grunden för all analys inom business intelligence är tid. Du vill se försäljning, lagervärden eller marknadsandelar under en vecka, ett år eller en månad. För att göra detta behöver du en tidsdimension till det fakta du vill analysera. Först skapar du en tabell som i mitt exempel heter dimDatum:


CREATE TABLE dbo.dimDatum (
datumNyckel INT NOT NULL,
dag DATETIME NOT NULL,
vecka INT NOT NULL,
manad INT NOT NULL,
kvartal INT NOT NULL,
ar INT NOT NULL,
dagimanad INT NOT NULL,
dagivecka INT NOT NULL,
arvecka INT NOT NULL,
manadmednoll NVARCHAR(2) NOT NULL,
dagnamn NVARCHAR(10) NOT NULL,
manadsnamn NVARCHAR(20) NOT NULL

CONSTRAINT PK_DimDatum_datumNyckel
PRIMARY KEY (datumNyckel)
)

I denna tabell finner du bland annat månad, år, dag och dagnamn, men också kolumnen manadmednoll, en kolumn som kan vara bra att ha när du ska “sätta ihop” datum åt olika håll.

För att populera denna tabell behöver vi loopa framåt eller bakåt. Jag har valt att skapa ett skript som går bakåt. Du kan ändra skriptet enkelt att gå framåt genom att sätta minusvärde på parametern @nrofdaysback.


DECLARE @CurrentDate AS DATETIME
DECLARE @NrOfDaysBack AS INT
DECLARE @CurrentDaysBack AS INT

SET @NrOfDaysBack = 2500
SET @CurrentDaysBack = 0

WHILE @CurrentDaysBack < @NrOfDaysBack BEGIN -- Ändra på minustecknet för att få värden för framtiden SET @CurrentDate = (SELECT DATEADD(D, -@CurrentDaysBack , GETDATE())) INSERT INTO dbo.dimDatum SELECT CAST(CONVERT(nvarchar(10), @CurrentDate, 112) as int) as datumNyckel, CAST(CONVERT(nvarchar(10), @CurrentDate, 112) as DATETIME) as Dag, DATEPART(WEEK,@CurrentDate) as vecka, MONTH(@CurrentDate) as manad, DATEPART(Q,@CurrentDate) as kvartal, YEAR(@CurrentDate) as ar, DATEPART(DD,@CurrentDate) as dagimanad, DATEPART(WEEKDAY,@CurrentDate) -1 as dagivecka, CASE WHEN DATEPART(WEEK,@CurrentDate) < 10 THEN CAST(YEAR(@CurrentDate) AS NVARCHAR(4)) + '0' + CAST(DATEPART(WEEK,@CurrentDate) AS NVARCHAR(2)) ELSE CAST(YEAR(@CurrentDate) AS NVARCHAR(4)) + CAST(DATEPART(WEEK,@CurrentDate) AS NVARCHAR(2)) END as arvecka, CASE WHEN MONTH(@CurrentDate) < 10 THEN '0' + CAST(MONTH(@CurrentDate) AS NVARCHAR(2)) ELSE CAST(MONTH(@CurrentDate) AS NVARCHAR(2)) END as manadmednoll, CASE WHEN DATEPART(WEEKDAY,@CurrentDate) -1 = 1 THEN 'Måndag' WHEN DATEPART(WEEKDAY,@CurrentDate) -1 = 2 THEN 'Tisdag' WHEN DATEPART(WEEKDAY,@CurrentDate) -1 = 3 THEN 'Onsdag' WHEN DATEPART(WEEKDAY,@CurrentDate) -1 = 4 THEN 'Torsdag' WHEN DATEPART(WEEKDAY,@CurrentDate) -1 = 5 THEN 'Fredag' WHEN DATEPART(WEEKDAY,@CurrentDate) -1 = 6 THEN 'Lördag' WHEN DATEPART(WEEKDAY,@CurrentDate) -1 = 0 THEN 'Söndag' END as dagnamn, CASE WHEN MONTH(@CurrentDate) = 1 THEN 'Januari' WHEN MONTH(@CurrentDate) = 2 THEN 'Februari' WHEN MONTH(@CurrentDate) = 3 THEN 'Mars' WHEN MONTH(@CurrentDate) = 4 THEN 'April' WHEN MONTH(@CurrentDate)= 5 THEN 'Maj' WHEN MONTH(@CurrentDate)= 6 THEN 'Juni' WHEN MONTH(@CurrentDate)= 7 THEN 'Juli' WHEN MONTH(@CurrentDate)= 8 THEN 'Augusti' WHEN MONTH(@CurrentDate)= 9 THEN 'September' WHEN MONTH(@CurrentDate)= 10 THEN 'Oktober' WHEN MONTH(@CurrentDate)= 11 THEN 'November' WHEN MONTH(@CurrentDate)= 12 THEN 'December' END as manadsnamn SET @CurrentDaysBack += 1 END

Och där har du din tidsdimension, redo att användas för att sortera fakta.

/R