0

Good day

I have a legacy database that was designed for a specific front end application. I am doing multiples cases of additional app development using this data however, the legacy database has proven inadequate to work with going into the future. Unfortunately the legacy database has to stay in place due to the fact that i still need the front end application running.

I have created a new database of similar structure that will be used, every time a vehicle (the example we'll use) is added to the legacy database through the front end application I have set up a trigger to push the specified data into the new database on insert (this is all working perfectly).

Now to get to my problem. Each vehicle is allocated a location key which describes which location it belongs to on the hierarchical tree structure of locations. I need to take this location which could be from any tree level and find all the nodes below and above it in the legacy database using the locations table, then add all the location keys of the nodes to the vehicle table in the new database which will comprise of 7 levels (columns). I only need to get Location 0,1,2,3,4,5,6,7.

For example I will have seven columns of which any may be the vehicles registered location.

(Level0Key, Level1Key, Level2key,...,...,..., Level6Key, Level7Key)

As I understand you'll need to see the legacy databases vehicles table, logical level table and locations table (where all locations are listed with there parent keys) in order to help me.

I will attach these tables and the simple trigger I have, I cannot explain how much id appreciate any help whether its a statement of logic or the coded trigger that might work (Bonus). A huge thanks in advance. I am just battling with exporting all the LocKeys to the variables @level1Key etc..

Locations Table

Logical levels table

Vehicles table

Code:

         SET ANSI_NULLS ON
    SET QUOTED_IDENTIFIER ON
    GO

    CREATE TRIGGER dbo.transferVehicle
    ON dbo.Vehicles
    AFTER INSERT 
    AS
    BEGIN
        SET NOCOUNT ON;

        DECLARE @Level0Key INT, @Level1Key INT, @Level2Key INT, @Level3Key INT, @Level4Key INT, @Level5Key INT,@Level6Key INT,@Level7Key INT, @LocKey INT;

        SELECT @LocKey = [LocKey] FROM Inserted ;

            with tbParent as
    (
        select * from Canepro.dbo.locations where LocKey= @LocKey
        union all
        select locations.* from Canepro.dbo.locations  join tbParent  on locations.LocKey = tbParent.ParentKey
    ),

        tbsons as
    (
        select * from Canepro.dbo.locations where LocKey= @LocKey
        union all
        select locations.* from Canepro.dbo.locations  join tbsons  on locations.ParentKey= tbsons.LocKey
    ),
        tball as
    (
        select * from  tbParent as p
        union 
        select * from tbsons as s

    ),
    final as
    (
    select number = ROW_NUMBER() OVER (ORDER BY t.LocKey), t.LocKey,t.LocName ,  t.ParentKey 
    from tball as t 
    )

    --I now need to export all rows (LocKeys) from final into the variables
    -- if i use two select statments (see below) i get an error on the second
select @LocKey1 = LocKey from final where number = 1
select @LocKey2 = Lockey from final where number = 2 


        INSERT INTO [NewDatabase].dbo.Vehicles (VehCode, VehicleNumber, RegistrationNumber, Description, FuelKey, CatKey, Active, ExpectedConsumption, IsPetrol, LicenseExpiryDate, FuelTankCapacity, OdometerReading, Level0LocKey, Level1LocKey, Level2LocKey,Level3LocKey, Level4LocKey, Level5LocKey, Level6LocKey, Level7Key)

            SELECT 
                VehCode, VehicleNumber, RegistrationNumber, Description, FuelType, CatKey, Active, ExpectedConsumption, IsPetrol, LicenseExpiryDate, FuelTankCapacity, OdometerReading, LocKey, @Level0Key, @Level1Key, @Level2Key, @Level3Key, @Level4Key, @Level5Key, @Level6Key, @Level7Key -- then all the other nodes that relate to the lockey, above and below is level from level0 (The top of the tree) to level 6 of the tree
            FROM   
                inserted;
    END
    GO

Expected input from insert:

Vkey : 185 
Lockey : 60000690
VehCode : 52
VehicleNumber : 80/11A52
RegistrationNumber :NUF 37746
Description : Ford 6610 4x4 (52)
FuelType : 174
CatKey : 7
Active : 1
Expected consumption : Null
IsPetrol : 0
LicenseExpiryDate : 2011-04-30 00:00:00
FuelTankCapacity : 150
OdomenterReading : Hours 

Expected output into new database :

Vkey : 185 
Lockey : 60000690
VehCode : 52
VehicleNumber : 80/11A52
RegistrationNumber :NUF 37746
Description : Ford 6610 4x4 (52)
FuelType : 174
CatKey : 7
Active : 1
Expected consumption : Null
IsPetrol : 0
LicenseExpiryDate : 2011-04-30 00:00:00
FuelTankCapacity : 150
OdomenterReading : Hours 
Level0Key : 60000291 (Top Tree node)
Level1Key : 60002764 (Second Level of tree)
Level2Key : 60000841 (third level of tree)
Level3Key : 60000177 (Fourth level of tree)
Level4Key : 60000179 (Fifth level of tree)
Level5Key : 60000181 (sixth level of tree)
Level6Key : 60000205 (seventh level of tree)
Level7Key : 60000690 (Eighth level of tree)  
( We can see this one is the same as the Lockey)

Would really really appreciate some help

  • 1
    Best to post sample data and desired results as text. – John Cappelletti Apr 15 '20 at 16:20
  • Hello John, do you think you'd be able to help me ? I feel as if I've provided enough information an context, please specify what more I can share in order to receive help ? – Matthew Leslie Apr 15 '20 at 19:03
  • @JohnCappelletti I would really really appreciate it. – Matthew Leslie Apr 15 '20 at 19:28
  • @JohnCappelletti I hope I have not been misunderstood, please specify what you mean by sample data (other than the photos I included), should I post an example of the input the legacy database would receive and the data I would then like to be processed in the trigger to be added to the new database ? I am trying to take your advice, thanks in advance – Matthew Leslie Apr 15 '20 at 19:41
  • @JohnCappelletti I will start getting this interpretation of sample data together while I await your reply, thanks again – Matthew Leslie Apr 15 '20 at 19:46
  • @JohnCappelletti Hello John, I have taken your advice and added sample data and desired results. I would really appreciate the help. – Matthew Leslie Apr 16 '20 at 09:10
  • Id also appreciate it if anyone could give me tips to why no one is answering this thread, thanks in advance ! – Matthew Leslie Apr 16 '20 at 12:47
  • @JohnCappelletti – Matthew Leslie Apr 16 '20 at 16:23
  • This is a long question and difficult to grasp. I'll read it three more times and see if I can get it – Nick.Mc Apr 19 '20 at 13:32
  • You have a tree with seven levels. Your input is a key that is anywhere in this hierarchy and you want to capture and return all levels? I think you could create a _much_ shorter question that focuses on this. It's very important that you represent `Locations` Table as DDL, not as a picture. Also note this table is self referencing which means it can represent a tree of any number of levels, _and_ these levels can be ragged (some branches are three deep, some are seventeen) – Nick.Mc Apr 19 '20 at 13:37
  • If you know for sure that it's only ever seven levels, I can think of a query to do it. But how many cars will this trigger need to handle per minute? I expect it will need to perform well otherwise the trigger will interfere with normal application operation – Nick.Mc Apr 19 '20 at 13:38
  • If you were to provide the Locations table DDL _and_ some insert statements to represent the data it would make it far easier to pose a solution – Nick.Mc Apr 19 '20 at 13:41
  • @Nick.McDermaid Thanks for your comments. I don't know there will only be 7 however i only need the top 7. I am working on getting the DLL and SELECTs to you. In the mean time please notice I have updated the code as I have made significant progress. I have a table named "final" that contain all the Parent and Child lockeys in order. I am now just battling with exporting each row into the variables eg "@level1key". final step before adding them to the insert however im now battling. – Matthew Leslie Apr 20 '20 at 17:21
  • @Nick.McDermaid the trigger will only handle vehicles when one is added to the database ( 2 a day at most) – Matthew Leslie Apr 20 '20 at 17:32
  • @Nick.McDermaid This is a little embarrassing but i don't know how to represent the table as a dll for you, other than manually typing each column and row ? sorry but if you give me a methodology I will instantly provide it to you. otherwise ill take the time now to provide you with a manually inserted text version – Matthew Leslie Apr 20 '20 at 17:34
  • @Nick.McDermaid I have moved this question over to a new question which is shorter and more specific to my problem at this time if youd like to refer to that : https://stackoverflow.com/questions/61329064/setting-multiple-variables-from-a-cte – Matthew Leslie Apr 20 '20 at 18:10
  • _DDL_, not _DLL_. DDL = Data Definition language. Generate a create script locations table as per this https://learn.microsoft.com/en-us/sql/ssms/scripting/generate-scripts-sql-server-management-studio?view=sql-server-ver15 Then generate some insert statements for data. Then I can run it on my own SQL Server and provide an answer – Nick.Mc Apr 21 '20 at 12:46
  • Are you absolutely certain it's a good idea to force a self referencing tree into seven levels? Will the location passed ever be at level 8? – Nick.Mc Apr 21 '20 at 13:02

1 Answers1

0

Problem 1

if i use two select statments (see below) i get an error on the second

This doesn't work because your CTE's disappear after the first statement. So you need to save the data into a work table.

Example:

-- Set up a table variable to save results into
DECLARE @WorkTable TABLE (LevelNumber INT,LocKey INT,ParentKey INT)

DECLARE @LocKey INT = 11;

        with tbParent as
(
    select * from [Location] where LocKey= @LocKey
    union all
    select [Location].* from [Location]  join tbParent  on [Location].LocKey = tbParent.ParentKey
),

    tbsons as
(
    select * from [Location] where LocKey= @LocKey
    union all
    select [Location].* from [Location]  join tbsons  on [Location].ParentKey= tbsons.LocKey
),
    tball as
(
    select * from  tbParent as p
    union 
    select * from tbsons as s

),
final as
(
select LevelNumber = ROW_NUMBER() OVER (ORDER BY t.LocKey), t.LocKey,  t.ParentKey 
from tball as t 
)

-- Save the results into the table variable
INSERT INTO @WorkTable (LevelNumber,LocKey,ParentKey)
SELECT LevelNumber,LocKey,ParentKey from final

-- now we can do what we like with the table variables
select @LocKey1 = LocKey from final where number = 1
select @LocKey2 = Lockey from final where number = 2 

But again I must caution you against forcing a self referencing tree into fixed levels unless you are certain the data always comes out this way.

Problem 2

SELECT @LocKey = [LocKey] FROM Inserted ;

INSERTED can contain many rows. This just gets the first one. If there is any operation that inserts or updates many rows, your trigger won't work properly. You need to loop (or join) inserted and work on every row in it.

Example of DDL and Inserts

Below is an example of table DDL and sample data. This allows us to set up your data and work with it locally.

CREATE TABLE [LOCATION] (LocKey INT , ParentKey INT , TreeLevel INT)

INSERT INTO [LOCATION]
SELECT LocKey,ParentKey,TreeLevel
FROM 
(
VALUES 
(1,60000291,1),
(2,50000199,6),
(6,60000706,8),
(7,60000707,8),
(8,6,9),
(9,6,9),
(10,6,9),
(11,6,9),
(12,6,9),
(13,6,9),
(14,6,9),
(15,6,9),
(16,6,9),
(17,6,9)
) As T(LocKey,ParentKey,TreeLevel)
Nick.Mc
  • 18,304
  • 6
  • 61
  • 91
  • Thank you so much Nick, really appreciate all your help. I had created a Temp table after the CTE, very grateful to learn about table variables. I am sure only one row will be inserted at a time and a vehicles key can never be below node 6 thank you for your expressing that worry though. Much appreciated and good luck with your future endeavors. – Matthew Leslie Apr 22 '20 at 13:12