SQL Problem

  • Hi clever sql people - could someone give their expertise here.

    I have a table that is used for the hierarchical structure of rooms in an organisation. Here is the makeup of the table

    location_id - parent - description

    1 - 205 - Bridge Laboratory

    2 - 1 - Flammable Store

    5 - 205 - Waste

    9 - 5 - Waste Station

    10 - 205 - Process Engineering

    Plus about a hundred more. In my web application I need to write some sql that will look for xpired chemical batches due to expire in the next thirty days. My problem is that I need to list the full location of each batch - and that is the problem - some locations have a location - and a sub location - but others have up to 5 or six sub locations. The way that I have tried to do this is by the following code. It is not correct as it goes to four levels but I am not dealing with what happens if there is a batch in a location where there is only one or two sublocations. Here is my code

    Use new_scitech

    SELECT dbo.[Employee Full].emp_user_id,

    dbo.compound.compound_nme,

    dbo.batch.batch_id,

    dbo.batch.compound_id,

    location_4.description AS Loc1,

    location_3.description AS Loc2,

    location_2.description AS Loc3,

    location_1.description AS Loc4,

    dbo.batch.expiry_dte

    FROM

    dbo.compound

    INNER JOIN dbo.batch ON dbo.compound.compound_id = dbo.batch.compound_id

    INNER JOIN dbo.location ON dbo.batch.location_id = dbo.location.location_id

    INNER JOIN dbo.[Employee Full] ON dbo.batch.create_by_emp_no = dbo.[Employee Full].emp_no

    INNER JOIN dbo.location location_1 ON dbo.location.location_id = location_1.location_id

    INNER JOIN dbo.location location_2 ON location_1.parent = location_2.location_id

    INNER JOIN dbo.location location_3 ON location_2.parent = location_3.location_id

    INNER JOIN dbo.location location_4 ON location_3.parent = location_4.location_id

    GROUP BY

    dbo.[Employee Full].emp_user_id,

    dbo.compound.compound_nme,

    location_4.description,

    location_3.description,

    location_2.description,

    location_1.description,

    dbo.batch.expiry_dte,

    dbo.batch.batch_id,

    dbo.batch.compound_id

    HAVING

    (dbo.batch.expiry_dte < GETDATE())

    ORDER BY

    dbo.[Employee Full].emp_user_id

    I guess what I need to do is put all locations into one field and put a '|' between them. Add a few more location tables and wrap the selects in a case statement that would put append a '' to any locations that return a null. I am not sure how to go about the joins for this so - if anyone can help that would be great.

    Great forum and thanks in advance

  • Hi

    I have'nt gone thru your post in detail.. sorry for that 🙂

    You could take a look at CTE 's for fetching hierarchial data.

    That way you wont have to worry abt levels of data.

    "Keep Trying"

  • I dont think it is available - I have SQL2008 (I know this is a 2005 forum)

  • SET ANSI_NULLS, QUOTED_IDENTIFIER ON

    GO

    CREATE FUNCTION dbo.GetLocationDescription

    (

    &nbsp&nbsp&nbsp&nbsp@location_id int

    )

    RETURNS varchar(8000)

    AS

    BEGIN

    &nbsp&nbsp&nbsp&nbspDECLARE @result varchar(8000)

    &nbsp&nbsp&nbsp&nbspSET @result = ''

    &nbsp&nbsp&nbsp;WITH cte (HLevel, Parent, [Description])

    &nbsp&nbsp&nbsp&nbspAS

    &nbsp&nbsp&nbsp&nbsp(

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspSELECT 1 AS HLevel, T1.Parent, T1.[Description]

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspFROM dbo.Location T1

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspWHERE T1.location_id = @location_id

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspUNION ALL

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspSELECT C2.HLevel + 1, T2.Parent, T2.[Description]

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspFROM dbo.Location T2

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspJOIN cte C2

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspON T2.location_id = C2.Parent

    &nbsp&nbsp&nbsp&nbsp)

    &nbsp&nbsp&nbsp&nbspSELECT @result = @result + C.[Description] + ' | '

    &nbsp&nbsp&nbsp&nbspFROM cte C

    &nbsp&nbsp&nbsp&nbspORDER BY C.HLevel DESC

    &nbsp&nbsp&nbsp&nbspRETURN LEFT(@result, LEN(@result) - 2)

    END

    GO

    SELECT E.emp_user_id

    &nbsp&nbsp&nbsp&nbsp,C.compound_nme

    &nbsp&nbsp&nbsp&nbsp,B.batch_id

    &nbsp&nbsp&nbsp&nbsp,B.compound_id

    &nbsp&nbsp&nbsp&nbsp,dbo.GetLocationDescription(B.location_id) AS Location

    &nbsp&nbsp&nbsp&nbsp,B.expiry_dte

    FROM dbo.compound C

    &nbsp&nbsp&nbsp&nbspJOIN dbo.batch B

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspON C.compound_id = B.compound_id

    &nbsp&nbsp&nbsp&nbspJOIN dbo.[Employee Full] E

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspON B.create_by_emp_no = E.emp_no

    WHERE B.expiry_dte < GETDATE()

    ORDER BY E.emp_user_id

  • Are'nt CTE's available in SQL 2008 ?

    "Keep Trying"

  • Hi There and thanks for the reply

    This problem has been dogging me now for oiver a week. When I copy this into query analyser to test I get two errors

    Server: Msg 156, Level 15, State 1, Procedure GetLocationDescription, Line 11

    Incorrect syntax near the keyword 'WITH'.

    Server: Msg 137, Level 15, State 1, Procedure GetLocationDescription, Line 21

    Must declare the variable '@t'.

    I am using sql server 2000 (I posted incorrectly earlier) does this version support CTE Recursion?

    Thanks for your help

  • SET ANSI_NULLS, QUOTED_IDENTIFIER ON

    GO

    CREATE FUNCTION dbo.GetLocationDescription

    (

    @location_id int

    )

    RETURNS varchar(8000)

    AS

    BEGIN

    &nbsp&nbsp&nbsp&nbspDECLARE @result varchar(8000)

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp,@Level int

    &nbsp&nbsp&nbsp&nbspSELECT @result = ''

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp,@Level = 1

    &nbsp&nbsp&nbsp&nbspDECLARE @cte TABLE

    &nbsp&nbsp&nbsp&nbsp(

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspHLevel int NOT NULL

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp,Parent int NOT NULL

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp,[Description] varchar(255) NOT NULL

    &nbsp&nbsp&nbsp&nbsp)

    &nbsp&nbsp&nbsp&nbspINSERT INTO @cte

    &nbsp&nbsp&nbsp&nbspSELECT @Level, T1.Parent, T1.[Description]

    &nbsp&nbsp&nbsp&nbspFROM dbo.Location T1

    &nbsp&nbsp&nbsp&nbspWHERE T1.location_id = @location_id

    &nbsp&nbsp&nbsp&nbspWHILE 1=1

    &nbsp&nbsp&nbsp&nbspBEGIN

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspSELECT C2.HLevel + 1, T2.Parent, T2.[Description]

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspFROM dbo.Location T2

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspJOIN @cte C2

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspON T2.location_id = C2.Parent

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspWHERE C2.HLevel = @Level

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspIF @@rowcount = 0

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspBREAK

    &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspSET @Level = @Level + 1

    &nbsp&nbsp&nbsp&nbspEND

    &nbsp&nbsp&nbsp&nbspSELECT @result = @result + C.[Description] + ' | '

    &nbsp&nbsp&nbsp&nbspFROM @cte C

    &nbsp&nbsp&nbsp&nbspORDER BY C.HLevel DESC

    &nbsp&nbsp&nbsp&nbspRETURN LEFT(@result, LEN(@result) - 2)

    END

    GO

  • Server: Msg 444, Level 16, State 2, Procedure GetLocationDescription, Line 27

    Select statements included within a function cannot return data to a client.

  • Add the INSERT INTO @cte which I forgot.

  • Could you show me where this needs to be inserted please

  • Add the insert into @cte does not make sense to me. The error message that I get indicates that you cannot return a recordset to the client from within a function. And this is a function!

Viewing 11 posts - 1 through 10 (of 10 total)

You must be logged in to reply to this topic. Login to reply