Advertisement
Guest User

SQLug 2014 Challenge Setup

a guest
Dec 9th, 2014
249
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
T-SQL 15.03 KB | None | 0 0
  1. /*
  2. -- Cleanup code
  3. drop procedure dbo.WarmupQueueReaders;
  4. drop table StartIt;
  5. drop procedure dbo.FillErsattning;
  6. drop procedure dbo.FillErsattningMem;
  7. drop table dbo.PrislistaMem;
  8. drop type dbo.BesokMemType;
  9. drop type dbo.VardenhetMemType;
  10. drop table dbo.ErsattningMem;
  11.  
  12. drop procedure dbo.SendMsg;
  13. drop procedure dbo.ReceiveMsg;
  14. drop procedure dbo.SQLugChallenge2014_TargetQueue_Procedure
  15.  
  16. drop service [//SQLugChallenge2014/InitiatorService];
  17. drop service [//SQLugChallenge2014/TargetService];
  18.  
  19. drop queue SQLugChallenge2014_InitiatorQueue;
  20. drop queue SQLugChallenge2014_TargetQueue;
  21.  
  22. drop contract [//SQLugChallenge2014/Contract]
  23.  
  24. drop message type [//SQLugChallenge2014/RequestMessage];
  25. drop message type [//SQLugChallenge2014/ReplyMessage];
  26. drop message type [//SQLugChallenge2014/WarmupMessage];
  27.  
  28. */
  29.  
  30. go
  31.  
  32. -- Enable Service Broker
  33. if (select is_broker_enabled from sys.databases where name = db_name()) = 0
  34. begin
  35.   alter database current set single_user with rollback immediate;
  36.   alter database current set enable_broker;
  37.   alter database current set multi_user;
  38. end;
  39.  
  40. create message type [//SQLugChallenge2014/RequestMessage] validation = well_formed_xml;
  41. create message type [//SQLugChallenge2014/ReplyMessage]  validation = well_formed_xml;
  42. create message type [//SQLugChallenge2014/WarmupMessage]  validation = well_formed_xml;
  43.  
  44. create contract [//SQLugChallenge2014/Contract]
  45. (
  46.   [//SQLugChallenge2014/RequestMessage] sent by initiator,
  47.   [//SQLugChallenge2014/ReplyMessage] sent by target,
  48.   [//SQLugChallenge2014/WarmupMessage] sent by initiator
  49. );
  50.  
  51. create queue dbo.SQLugChallenge2014_TargetQueue;
  52. create service [//SQLugChallenge2014/TargetService] on queue dbo.SQLugChallenge2014_TargetQueue ([//SQLugChallenge2014/Contract]);
  53.  
  54. create queue dbo.SQLugChallenge2014_InitiatorQueue;
  55. create service [//SQLugChallenge2014/InitiatorService] on queue dbo.SQLugChallenge2014_InitiatorQueue;
  56.  
  57. go
  58.  
  59. -- Gatekeeper for queuereaders
  60. create table dbo.StartIt
  61. (
  62.   PK bit not null primary key nonclustered hash with (bucket_count = 1)
  63. ) with (memory_optimized = on, durability = schema_only);
  64.  
  65. go
  66.  
  67. insert into dbo.StartIt(PK) values(0);
  68.  
  69. go
  70.  
  71. -- Holds Prislista in memory
  72. create table dbo.PrislistaMem
  73. (
  74.   Taxekod char(3) collate Finnish_Swedish_100_BIN2 not null primary key nonclustered hash with (bucket_count = 16),
  75.   Pris int not null
  76. ) with (memory_optimized = on, durability = schema_only);
  77.  
  78. go
  79.  
  80. -- Table valued parameter to dbo.FillErsattningMem
  81. create type dbo.BesokMemType as table
  82. (
  83.   ID int not null primary key nonclustered hash with (bucket_count = 524288),
  84.   PatientID uniqueidentifier not null,
  85.   Taxekod char(3) collate Finnish_Swedish_100_BIN2 not null,
  86.   Datum date not null,
  87.   Pris int not null
  88. ) with (memory_optimized = on);
  89. go
  90.  
  91. -- Holds a unique list of Vardenhet
  92. create type dbo.VardenhetMemType as table
  93. (
  94.   Vardenhet char(5) collate Finnish_Swedish_100_BIN2 not null primary key nonclustered,
  95.   index IX_VardenehetMem nonclustered (Vardenhet)
  96. ) with (memory_optimized = on);
  97. go
  98.  
  99. -- Result of dbo.FillErsattningMem
  100. create table dbo.ErsattningMem
  101. (
  102.   Vardenhet char(5) collate Finnish_Swedish_100_BIN2 not null,
  103.   Datum date not null,
  104.   Belopp int not null,
  105.   index IX_ErsattningMem nonclustered (Vardenhet, Datum)
  106. ) with (memory_optimized = on, durability = schema_only);
  107.  
  108. go
  109.  
  110. -- Execute once per Vardehet to calculate Belopp per date and patient
  111. create procedure dbo.FillErsattningMem
  112.   @Vardenhet char(5),
  113.   @BesokMem dbo.BesokMemType readonly
  114. with native_compilation, schemabinding, execute as owner
  115. as
  116. begin atomic with (transaction isolation level = snapshot, language = N'us_english', delayed_durability = on)
  117.   declare @ID int = 0;
  118.   declare @RowsLeft bit = 1;
  119.   declare @LastPatientID uniqueidentifier;
  120.   declare @CurPatientID uniqueidentifier;
  121.   declare @LastDate date;
  122.   declare @CurDate date;
  123.   declare @Belopp int = 0;
  124.   declare @Taxekod char(3);
  125.   declare @Pris int;
  126.   declare @MaxA int = 0;
  127.   declare @SumB int = 0;
  128.   declare @MaxK12 int = 0;
  129.   declare @MaxK34 int = 0;
  130.   declare @MaxT1 int = 0;
  131.   declare @MaxT2 int = 0;
  132.   declare @LastT1Date date = '0001-01-01';
  133.   declare @LastT2Date date = '0001-01-01';
  134.  
  135.   select @LastDate = B.Datum,
  136.          @LastPatientID = B.PatientID
  137.   from @BesokMem as B
  138.   where B.ID = 1
  139.  
  140.   while @RowsLeft = 1
  141.   begin
  142.     set @ID += 1;
  143.  
  144.     select @CurDate = B.Datum,
  145.            @CurPatientID = B.PatientID,
  146.            @Taxekod = B.Taxekod,
  147.            @Pris = B.Pris
  148.     from @BesokMem as B
  149.     where B.ID = @ID
  150.  
  151.     if @@rowcount = 1
  152.     begin
  153.       if @LastPatientID <> @CurPatientID
  154.       begin
  155.         -- New patient
  156.         set @Belopp = @MaxA;
  157.         if @Belopp < @MaxK12 + @MaxK34 set @Belopp = @MaxK12 + @MaxK34;
  158.         if datediff(day, @LastT1Date, @LastDate) <= 90 set @MaxT1 = 0;
  159.         if datediff(day, @LastT2Date, @LastDate) <= 90 set @MaxT2 = 0;
  160.         if @Belopp < @MaxT1 set @Belopp = @MaxT1;
  161.         if @Belopp < @MaxT2 set @Belopp = @MaxT2;
  162.  
  163.         if @Belopp + @SumB > 0
  164.         begin
  165.           insert into dbo.ErsattningMem(Vardenhet, Datum, Belopp) values
  166.             (@Vardenhet, @LastDate, @Belopp + @SumB);
  167.         end;
  168.  
  169.         select @MaxA = 0,
  170.                @SumB = 0,
  171.                @MaxK12 = 0,
  172.                @MaxK34 = 0,
  173.                @MaxT1 = 0,
  174.                @MaxT2 = 0,
  175.                @LastT1Date = '0001-01-01',
  176.                @LastT2Date = '0001-01-01',
  177.                @LastDate = @CurDate,
  178.                @LastPatientID = @CurPatientID;
  179.       end
  180.       else
  181.       if @LastDate <> @CurDate
  182.       begin
  183.         -- New date same patient
  184.         set @Belopp = @MaxA;
  185.         if @Belopp < @MaxK12 + @MaxK34 set @Belopp = @MaxK12 + @MaxK34;
  186.         if datediff(day, @LastT1Date, @LastDate) <= 90 set @MaxT1 = 0;
  187.         if datediff(day, @LastT2Date, @LastDate) <= 90 set @MaxT2 = 0;
  188.  
  189.         if @MaxT1 >= @MaxT2
  190.         begin
  191.           if @Belopp < @MaxT1
  192.           begin
  193.             set @Belopp = @MaxT1;
  194.             set @LastT1Date = @LastDate;
  195.           end
  196.         end
  197.         else
  198.         begin
  199.           if @Belopp < @MaxT2
  200.           begin
  201.             set @Belopp = @MaxT2;
  202.             set @LastT2Date = @LastDate;
  203.           end
  204.         end;
  205.  
  206.         if @Belopp + @SumB > 0
  207.         begin
  208.           insert into dbo.ErsattningMem(Vardenhet, Datum, Belopp) values
  209.             (@Vardenhet, @LastDate, @Belopp + @SumB);
  210.         end;
  211.        
  212.         select @Belopp = 0,
  213.                @MaxA = 0,
  214.                @SumB = 0,
  215.                @MaxK12 = 0,
  216.                @MaxK34 = 0,
  217.                @MaxT1 = 0,
  218.                @MaxT2 = 0,
  219.                @LastDate = @CurDate;
  220.       end;
  221.  
  222.       -- Gather max values per day and patient
  223.       if      @Taxekod = 'A01' and @Pris > @MaxA   set @MaxA = @Pris  
  224.       else if @Taxekod = 'A02' and @Pris > @MaxA   set @MaxA = @Pris  
  225.       else if @Taxekod = 'B01'                     set @SumB += @Pris  
  226.       else if @Taxekod = 'B02'                     set @SumB += @Pris  
  227.       else if @Taxekod = 'K01' and @Pris > @MaxK12 set @MaxK12 = @Pris
  228.       else if @Taxekod = 'K02' and @Pris > @MaxK12 set @MaxK12 = @Pris
  229.       else if @Taxekod = 'K03' and @Pris > @MaxK34 set @MaxK34 = @Pris
  230.       else if @Taxekod = 'K04' and @Pris > @MaxK34 set @MaxK34 = @Pris
  231.       else if @Taxekod = 'T01' and @Pris > @MaxT1  set @MaxT1 = @Pris  
  232.       else if @Taxekod = 'T02' and @Pris > @MaxT2  set @MaxT2 = @Pris;
  233.     end
  234.     else
  235.     begin
  236.       -- Last row
  237.       set @Belopp = @MaxA;
  238.       if @Belopp < @MaxK12 + @MaxK34 set @Belopp = @MaxK12 + @MaxK34;
  239.       if datediff(day, @LastT1Date, @CurDate) <= 90 set @MaxT1 = 0;
  240.       if datediff(day, @LastT2Date, @CurDate) <= 90 set @MaxT2 = 0;
  241.       if @Belopp < @MaxT1 set @Belopp = @MaxT1;
  242.       if @Belopp < @MaxT2 set @Belopp = @MaxT2;
  243.  
  244.       if @Belopp + @SumB > 0
  245.       begin
  246.         insert into dbo.ErsattningMem(Vardenhet, Datum, Belopp) values
  247.           (@Vardenhet, @LastDate, @Belopp + @SumB);
  248.       end;
  249.  
  250.       set @RowsLeft = 0;
  251.     end
  252.   end;
  253. end;
  254.  
  255. go
  256.  
  257. -- Called from dbo.SQLugChallenge2014_TargetQueue_Procedure once per Vardenhet
  258. create procedure dbo.FillErsattning
  259.   @Vardenhet char(5)
  260. as
  261. begin
  262.   set nocount on;
  263.  
  264.   declare @B dbo.BesokMemType;
  265.  
  266.   -- Get besok rows for one Vardenhet
  267.   insert into @B(ID, PatientID, Taxekod, Datum, Pris)
  268.   select row_number() over(order by B.PatientID, B.DatumOchTid), B.PatientID, B.Taxekod, cast(B.DatumOchTid as date), P.Pris
  269.   from dbo.Besok as B
  270.     inner join dbo.PrislistaMem as P
  271.       on B.Taxekod = P.Taxekod
  272.   where B.Vardenhet = @Vardenhet;
  273.  
  274.   -- Calucalte Belopp to dbo.ErsattningMem
  275.   exec dbo.FillErsattningMem @Vardenhet, @B;
  276.  
  277.   -- Add rows to Ersattning
  278.   insert into dbo.Ersattning(Vardenhet, Datum, Belopp)
  279.   select @Vardenhet, E.Datum, sum(E.Belopp)
  280.   from dbo.ErsattningMem as E
  281.   where E.Vardenhet = @Vardenhet
  282.   group by E.Datum;
  283.  
  284. end;
  285.  
  286. go
  287.  
  288. -- Target procedure for service borker queue
  289. create procedure dbo.SQLugChallenge2014_TargetQueue_Procedure
  290. as
  291. begin
  292.   set nocount on;
  293.  
  294.   declare @DlgHandle uniqueidentifier;
  295.   declare @Msg xml;
  296.   declare @MsgType sysname;
  297.   declare @Vardenhet char(5);
  298.  
  299.   while 1 = 1
  300.   begin
  301.     -- Get one message
  302.     waitfor
  303.     (
  304.       receive top(1) @DlgHandle = conversation_handle,
  305.                      @Msg = message_body,
  306.                      @MsgType = message_type_name
  307.       from dbo.SQLugChallenge2014_TargetQueue
  308.     ), timeout 1000;
  309.  
  310.     if @@rowcount = 0
  311.     begin
  312.       break;
  313.     end
  314.  
  315.     if @MsgType = N'//SQLugChallenge2014/RequestMessage'
  316.     begin
  317.       -- Process one Vardenhet and send a reply
  318.       set @Vardenhet = @Msg.value('(/E/text())[1]', 'char(5)');
  319.       if @Vardenhet is not null
  320.       begin
  321.         exec dbo.FillErsattning @Vardenhet;
  322.         send on conversation @DlgHandle message type [//SQLugChallenge2014/ReplyMessage](@Msg);
  323.       end;
  324.     end
  325.     if @MsgType = N'//SQLugChallenge2014/WarmupMessage'
  326.     begin
  327.       -- Wait for start signal
  328.       while 1 = 1
  329.       begin
  330.         waitfor delay '00:00:00.1';
  331.         if not exists(select * from dbo.StartIt)
  332.         begin
  333.           break;
  334.         end
  335.       end
  336.     end
  337.     else
  338.     if @MsgType = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
  339.     begin
  340.       -- Initiator wants to end conversation
  341.       end conversation @DlgHandle;
  342.     end
  343.     else
  344.     if @MsgType = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error'
  345.     begin
  346.       -- Something went wrong
  347.       declare @Error int;
  348.       declare @Description nvarchar(4000);
  349.  
  350.       with xmlnamespaces(default 'http://schemas.microsoft.com/SQL/ServiceBroker/Error')
  351.       select @Error = @Msg.value('(//Error/Code/text())[1]', 'int'),
  352.              @Description = @Msg.value('(//Error/Description/text())[1]', 'nvarchar(4000)');
  353.    
  354.       raiserror(N'Error Code:%i Description:"%s"', 16, 1, @Error, @Description) with log;
  355.  
  356.       end conversation @DlgHandle;
  357.     end
  358.   end
  359. end;
  360.  
  361. go
  362.  
  363. -- Generate one message per Vardenhet
  364. create procedure dbo.SendMsg
  365.   @NumMsgs int out
  366. as
  367. begin
  368.   set nocount on;  
  369.  
  370.   declare @E dbo.VardenhetMemType;
  371.   declare @DlgHandle uniqueidentifier;
  372.   declare @SQL nvarchar(max);
  373.  
  374.   -- Get unique list of Vardenhet
  375.   with E as
  376.   (
  377.     select top (1) B.Vardenhet
  378.     from dbo.Besok as B
  379.     order by B.Vardenhet
  380.     union all
  381.     select R.Vardenhet
  382.     from (
  383.           select B.Vardenhet,
  384.                 row_number() over (order by B.Vardenhet) as rn
  385.           from dbo.Besok as B
  386.             inner join E
  387.               on E.Vardenhet < B.Vardenhet
  388.           ) as R
  389.     where R.rn = 1
  390.   )
  391.   insert into @E(Vardenhet)
  392.   select E.Vardenhet
  393.   from E
  394.   option (maxrecursion 0);
  395.  
  396.   set @NumMsgs = @@rowcount;
  397.  
  398.   -- Build code to send one message per Vardenhet
  399.   set @SQL =
  400.   (
  401.     select N'send on conversation @DlgHandle message type [//SQLugChallenge2014/RequestMessage] (''<E>'+Vardenhet+N'</E>'');'+nchar(13)+nchar(10)
  402.     from @E
  403.     for xml path(''), type
  404.   ).value('text()[1]', 'nvarchar(max)')
  405.  
  406.   -- Start dialog with target
  407.   begin dialog @DlgHandle
  408.   from service [//SQLugChallenge2014/InitiatorService]
  409.   to service '//SQLugChallenge2014/TargetService'
  410.   on contract [//SQLugChallenge2014/Contract]
  411.   with encryption = off;
  412.  
  413.   -- Send messages
  414.   exec sp_executesql @SQL, N'@DlgHandle uniqueidentifier', @DlgHandle;
  415.  
  416. end;
  417.  
  418. go
  419.  
  420. -- Receive replies from target when processing is done
  421. create procedure dbo.ReceiveMsg
  422.   @NumMsgs int
  423. as
  424. begin
  425.   set nocount on;
  426.  
  427.   declare @DlgHandle uniqueidentifier;
  428.   declare @Msg xml;
  429.   declare @MsgType sysname;
  430.   declare @I int = 0
  431.  
  432.   set @I = 0;
  433.  
  434.   while 1 = 1
  435.   begin
  436.     -- Get one reply message
  437.     waitfor
  438.     (
  439.       receive top(1) @DlgHandle = conversation_handle,
  440.                      @Msg = message_body,
  441.                      @MsgType = message_type_name
  442.       from dbo.SQLugChallenge2014_InitiatorQueue
  443.     ), timeout 5000;
  444.  
  445.     if @MsgType = N'//SQLugChallenge2014/ReplyMessage'
  446.     begin
  447.       -- Count number of replies
  448.       set @I += 1;
  449.       if @I >= @NumMsgs
  450.       begin
  451.         -- Processing done, end conversation
  452.         end conversation @DlgHandle;
  453.         break;
  454.       end;
  455.     end
  456.     else
  457.     if @MsgType = N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
  458.     begin
  459.       -- Target wants to end dialog
  460.       end conversation @DlgHandle;
  461.     end
  462.     else
  463.     if @MsgType = N'http://schemas.microsoft.com/SQL/ServiceBroker/Error'
  464.     begin
  465.       -- Something went wrong
  466.       declare @Error int;
  467.       declare @Description nvarchar(4000);
  468.  
  469.       with xmlnamespaces(default 'http://schemas.microsoft.com/SQL/ServiceBroker/Error')
  470.       select @Error = @Msg.value('(//Error/Code/text())[1]', 'int'),
  471.              @Description = @Msg.value('(//Error/Description/text())[1]', 'nvarchar(4000)');
  472.    
  473.       raiserror(N'Error Code:%i Description:"%s"', 16, 1, @Error, @Description) with log;
  474.  
  475.       end conversation @DlgHandle;
  476.     end
  477.   end;
  478. end;
  479.  
  480. go
  481.  
  482. create procedure dbo.WarmupQueueReaders
  483. as
  484. begin
  485.   declare @DlgHandle uniqueidentifier;
  486.  
  487.   begin dialog @DlgHandle
  488.   from service [//SQLugChallenge2014/InitiatorService]
  489.   to service '//SQLugChallenge2014/TargetService'
  490.   on contract [//SQLugChallenge2014/Contract]
  491.   with encryption = off;
  492.  
  493.   send on conversation @DlgHandle message type [//SQLugChallenge2014/WarmupMessage];
  494.   end conversation @DlgHandle;
  495. end
  496.  
  497. go
  498.  
  499. -- Hook to dbo.SQLugChallenge2014_TargetQueue_Procedure SQLugChallenge2014_TargetQueue
  500. alter queue SQLugChallenge2014_TargetQueue with activation
  501. (
  502.   status = on,
  503.   procedure_name = dbo.SQLugChallenge2014_TargetQueue_Procedure,
  504.   max_queue_readers = 8,
  505.   execute as owner
  506. );
  507.  
  508. go
  509.  
  510. -- Add 8 messages to the queue. One for each queuereader
  511. exec dbo.WarmupQueueReaders;
  512. exec dbo.WarmupQueueReaders;
  513. exec dbo.WarmupQueueReaders;
  514. exec dbo.WarmupQueueReaders;
  515. exec dbo.WarmupQueueReaders;
  516. exec dbo.WarmupQueueReaders;
  517. exec dbo.WarmupQueueReaders;
  518. exec dbo.WarmupQueueReaders;
  519.  
  520. -- Wait for the queuemonitor to fire up the readers
  521. waitfor delay '00:00:40';
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement