Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. Database & SysAdmin
  3. Database
  4. how to union some table in a while loop to a table

how to union some table in a while loop to a table

Scheduled Pinned Locked Moved Database
questiondatabaseperformancehelptutorial
9 Posts 5 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    mhd sbt
    wrote on last edited by
    #1

    hi to all i have a while loop like this

    declare @Counter int
    while(@Counter<1000)
    begin
    set @Counter = @Counter + 1
    select * from mytable where [my where clause]
    end

    my where cluase change in each repeat. i want to union all result to a table and return one table as query result how can i do this ? performance is very important for me because while loop can be run for upper 15000 thanks for any help

    Richard DeemingR C 2 Replies Last reply
    0
    • M mhd sbt

      hi to all i have a while loop like this

      declare @Counter int
      while(@Counter<1000)
      begin
      set @Counter = @Counter + 1
      select * from mytable where [my where clause]
      end

      my where cluase change in each repeat. i want to union all result to a table and return one table as query result how can i do this ? performance is very important for me because while loop can be run for upper 15000 thanks for any help

      Richard DeemingR Offline
      Richard DeemingR Offline
      Richard Deeming
      wrote on last edited by
      #2

      mehdi.sabet wrote:

      my where cluase change in each repeat.

      Can you post your where clause? It can probably be replaced with a single query, which will give you much better performance.


      "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

      "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

      M 1 Reply Last reply
      0
      • Richard DeemingR Richard Deeming

        mehdi.sabet wrote:

        my where cluase change in each repeat.

        Can you post your where clause? It can probably be replaced with a single query, which will give you much better performance.


        "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

        M Offline
        M Offline
        mhd sbt
        wrote on last edited by
        #3

        hello thanks for reply my main code is:

        ALTER PROCEDURE [dbo].[lfd__GetFullPersonnelDetails]
        (
        @PersonnelList nvarchar(MAX),
        @WorkPeriodID int,
        @WorkPeriodYear int
        ) AS
        Declare @startDate SMALLDATETIME
        Declare @endDate SMALLDATETIME
        Declare @PersonnelBaseID INT

        WHILE(LEN(@PersonnelList) > 0)
        BEGIN
        SET @PersonnelBaseID = SUBSTRING(@PersonnelList, 0, PATINDEX('%,%',@PersonnelList))
        IF(@PersonnelBaseID != 0)
        SET @PersonnelList = SUBSTRING(@PersonnelList, LEN(CAST (@PersonnelBaseID AS NVARCHAR) + ',') + 1, LEN(@PersonnelList))
        ELSE
        BEGIN
        SET @PersonnelBaseID=CAST(@PersonnelList AS INT)
        SET @PersonnelList = SUBSTRING(@PersonnelList, LEN(@PersonnelList + ',') + 1, LEN(@PersonnelList))
        END

         set @startDate=(select top 1 \[date\] as startdate 
        	from 
        		lfd\_DailyStatistics
        	 where 
        		PersonnelBaseID = @PersonnelBaseID and \[Year\] = @WorkPeriodYear and  WorkingPeriodID = @WorkPeriodID 
        	order by date asc)
        
         set @endDate=(select top 1 \[date\] as startdate 
        	from 
        		lfd\_DailyStatistics
        	 where 
        		PersonnelBaseID = @PersonnelBaseID and \[Year\] = @WorkPeriodYear and  WorkingPeriodID = @WorkPeriodID 
        	order by date desc)
        
        SELECT 
        	dailyAbsences.\*,
        	CAST(CASE WHEN calculationQueue.\[StartDate\] IS NULL THEN 0 ELSE 1 END AS bit) AS \[NeedsRecalculation\] 
        FROM 
        	lfd\_dailyAbsence dailyAbsences LEFT JOIN
        	lfd\_CalculationQueue calculationQueue ON dailyAbsences.\[PersonnelBaseID\] = calculationQueue.\[PersonnelBaseID\] AND calculationQueue.\[StartDate\] <= @endDate 
        WHERE 
        	dailyAbsences.\[PersonnelBaseID\] = @PersonnelBaseID AND
        	dailyAbsences.\[StartDate\] >= @startDate AND 
        	dailyAbsences.\[EndDate\] <= DATEADD(day, 1, @endDate)
        ORDER BY
        	dailyAbsences.\[StartDate\]
        

        END

        start date and end date change in each repeat

        G Richard DeemingR 2 Replies Last reply
        0
        • M mhd sbt

          hi to all i have a while loop like this

          declare @Counter int
          while(@Counter<1000)
          begin
          set @Counter = @Counter + 1
          select * from mytable where [my where clause]
          end

          my where cluase change in each repeat. i want to union all result to a table and return one table as query result how can i do this ? performance is very important for me because while loop can be run for upper 15000 thanks for any help

          C Offline
          C Offline
          Corporal Agarn
          wrote on last edited by
          #4

          Why not create a temp table and insert the results there? When the while loop is done select * from your temp table.

          M 1 Reply Last reply
          0
          • C Corporal Agarn

            Why not create a temp table and insert the results there? When the while loop is done select * from your temp table.

            M Offline
            M Offline
            mhd sbt
            wrote on last edited by
            #5

            ok but what about performance ? if i done this and this loop execute ,for example , for 15000 repeat this is a optimal way? and how can use one temp table and insert all resualt to this temp table? thank you

            L 1 Reply Last reply
            0
            • M mhd sbt

              hello thanks for reply my main code is:

              ALTER PROCEDURE [dbo].[lfd__GetFullPersonnelDetails]
              (
              @PersonnelList nvarchar(MAX),
              @WorkPeriodID int,
              @WorkPeriodYear int
              ) AS
              Declare @startDate SMALLDATETIME
              Declare @endDate SMALLDATETIME
              Declare @PersonnelBaseID INT

              WHILE(LEN(@PersonnelList) > 0)
              BEGIN
              SET @PersonnelBaseID = SUBSTRING(@PersonnelList, 0, PATINDEX('%,%',@PersonnelList))
              IF(@PersonnelBaseID != 0)
              SET @PersonnelList = SUBSTRING(@PersonnelList, LEN(CAST (@PersonnelBaseID AS NVARCHAR) + ',') + 1, LEN(@PersonnelList))
              ELSE
              BEGIN
              SET @PersonnelBaseID=CAST(@PersonnelList AS INT)
              SET @PersonnelList = SUBSTRING(@PersonnelList, LEN(@PersonnelList + ',') + 1, LEN(@PersonnelList))
              END

               set @startDate=(select top 1 \[date\] as startdate 
              	from 
              		lfd\_DailyStatistics
              	 where 
              		PersonnelBaseID = @PersonnelBaseID and \[Year\] = @WorkPeriodYear and  WorkingPeriodID = @WorkPeriodID 
              	order by date asc)
              
               set @endDate=(select top 1 \[date\] as startdate 
              	from 
              		lfd\_DailyStatistics
              	 where 
              		PersonnelBaseID = @PersonnelBaseID and \[Year\] = @WorkPeriodYear and  WorkingPeriodID = @WorkPeriodID 
              	order by date desc)
              
              SELECT 
              	dailyAbsences.\*,
              	CAST(CASE WHEN calculationQueue.\[StartDate\] IS NULL THEN 0 ELSE 1 END AS bit) AS \[NeedsRecalculation\] 
              FROM 
              	lfd\_dailyAbsence dailyAbsences LEFT JOIN
              	lfd\_CalculationQueue calculationQueue ON dailyAbsences.\[PersonnelBaseID\] = calculationQueue.\[PersonnelBaseID\] AND calculationQueue.\[StartDate\] <= @endDate 
              WHERE 
              	dailyAbsences.\[PersonnelBaseID\] = @PersonnelBaseID AND
              	dailyAbsences.\[StartDate\] >= @startDate AND 
              	dailyAbsences.\[EndDate\] <= DATEADD(day, 1, @endDate)
              ORDER BY
              	dailyAbsences.\[StartDate\]
              

              END

              start date and end date change in each repeat

              G Offline
              G Offline
              GuyThiebaut
              wrote on last edited by
              #6

              Little tip - get rid of the order by clause - as it is taking up unnecessary processing time. You can order the results once you have combined them.

              “That which can be asserted without evidence, can be dismissed without evidence.”

              ― Christopher Hitchens

              1 Reply Last reply
              0
              • M mhd sbt

                hello thanks for reply my main code is:

                ALTER PROCEDURE [dbo].[lfd__GetFullPersonnelDetails]
                (
                @PersonnelList nvarchar(MAX),
                @WorkPeriodID int,
                @WorkPeriodYear int
                ) AS
                Declare @startDate SMALLDATETIME
                Declare @endDate SMALLDATETIME
                Declare @PersonnelBaseID INT

                WHILE(LEN(@PersonnelList) > 0)
                BEGIN
                SET @PersonnelBaseID = SUBSTRING(@PersonnelList, 0, PATINDEX('%,%',@PersonnelList))
                IF(@PersonnelBaseID != 0)
                SET @PersonnelList = SUBSTRING(@PersonnelList, LEN(CAST (@PersonnelBaseID AS NVARCHAR) + ',') + 1, LEN(@PersonnelList))
                ELSE
                BEGIN
                SET @PersonnelBaseID=CAST(@PersonnelList AS INT)
                SET @PersonnelList = SUBSTRING(@PersonnelList, LEN(@PersonnelList + ',') + 1, LEN(@PersonnelList))
                END

                 set @startDate=(select top 1 \[date\] as startdate 
                	from 
                		lfd\_DailyStatistics
                	 where 
                		PersonnelBaseID = @PersonnelBaseID and \[Year\] = @WorkPeriodYear and  WorkingPeriodID = @WorkPeriodID 
                	order by date asc)
                
                 set @endDate=(select top 1 \[date\] as startdate 
                	from 
                		lfd\_DailyStatistics
                	 where 
                		PersonnelBaseID = @PersonnelBaseID and \[Year\] = @WorkPeriodYear and  WorkingPeriodID = @WorkPeriodID 
                	order by date desc)
                
                SELECT 
                	dailyAbsences.\*,
                	CAST(CASE WHEN calculationQueue.\[StartDate\] IS NULL THEN 0 ELSE 1 END AS bit) AS \[NeedsRecalculation\] 
                FROM 
                	lfd\_dailyAbsence dailyAbsences LEFT JOIN
                	lfd\_CalculationQueue calculationQueue ON dailyAbsences.\[PersonnelBaseID\] = calculationQueue.\[PersonnelBaseID\] AND calculationQueue.\[StartDate\] <= @endDate 
                WHERE 
                	dailyAbsences.\[PersonnelBaseID\] = @PersonnelBaseID AND
                	dailyAbsences.\[StartDate\] >= @startDate AND 
                	dailyAbsences.\[EndDate\] <= DATEADD(day, 1, @endDate)
                ORDER BY
                	dailyAbsences.\[StartDate\]
                

                END

                start date and end date change in each repeat

                Richard DeemingR Offline
                Richard DeemingR Offline
                Richard Deeming
                wrote on last edited by
                #7

                OK, the first thing you need is a split function:

                CREATE FUNCTION dbo.fn_Split
                (
                @Value varchar(max),
                @Delimiter varchar(20) = ','
                )
                Returns TABLE
                As Return
                (
                WITH cte (Idx, StartIndex, EndIndex) As
                (
                SELECT
                1,
                1,
                CharIndex(@Delimiter, @Value)

                    UNION ALL
                    
                    SELECT 
                        1 + Idx, 
                        CAST(1 + EndIndex As int), 
                        CharIndex(@Delimiter, @Value, 1 + EndIndex)
                    FROM 
                        cte
                    WHERE
                        EndIndex > 0
                )
                SELECT
                    Idx,
                    SubString(@Value, StartIndex, CASE
                        WHEN EndIndex > 0 THEN EndIndex - StartIndex
                        ELSE LEN(@Value)
                    END) As Value
                FROM
                    cte
                

                );
                GO

                Then you can build a single query:

                WITH ctePersonnelList (PersonnelBaseID) As
                (
                SELECT
                CASE
                WHEN Value Like '%[^0-9]%' THEN Null
                ELSE CAST(Value As int)
                END
                FROM
                dbo.fn_Split(@PersonnelList, ',')
                WHERE
                Value Not Like '%[^0-9]%'
                ),
                cteDates (PersonnelBaseID, StartDate, EndDate) As
                (
                SELECT
                L.PersonnelBaseID,
                Min([date]),
                Max([date])
                FROM
                ctePersonnelList As L
                INNER JOIN lfd_DailyStatistics As S
                ON L.PersonnelBaseID = S.PersonnelBaseID
                WHERE
                [Year] = @WorkPeriodYear
                And
                WorkingPeriodID = @WorkPeriodID
                GROUP BY
                L.PersonnelBaseID
                )
                SELECT
                A.*,
                CAST(CASE WHEN Q.StartDate IS NULL THEN 0 ELSE 1 END AS bit) As NeedsRecalculation
                FROM
                cteDates As D
                INNER JOIN lfd_dailyAbsence As A
                ON A.PersonnelBaseID = D.PersonnelBaseID
                And A.StartDate >= D.StartDate
                And A.EndDate <= DateAdd(day, 1, D.EndDate)
                LEFT JOIN lfd_CalculationQueue As Q
                ON A.PersonnelBaseID = Q.PersonnelBaseID
                And Q.StartDate <= D.EndDate
                ORDER BY
                A.PersonnelBaseID,
                A.StartDate
                ;


                "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                M 1 Reply Last reply
                0
                • M mhd sbt

                  ok but what about performance ? if i done this and this loop execute ,for example , for 15000 repeat this is a optimal way? and how can use one temp table and insert all resualt to this temp table? thank you

                  L Offline
                  L Offline
                  Lost User
                  wrote on last edited by
                  #8

                  Looping in a database is never efficient. Working with tables is. Did that answer your question?

                  Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^]

                  1 Reply Last reply
                  0
                  • Richard DeemingR Richard Deeming

                    OK, the first thing you need is a split function:

                    CREATE FUNCTION dbo.fn_Split
                    (
                    @Value varchar(max),
                    @Delimiter varchar(20) = ','
                    )
                    Returns TABLE
                    As Return
                    (
                    WITH cte (Idx, StartIndex, EndIndex) As
                    (
                    SELECT
                    1,
                    1,
                    CharIndex(@Delimiter, @Value)

                        UNION ALL
                        
                        SELECT 
                            1 + Idx, 
                            CAST(1 + EndIndex As int), 
                            CharIndex(@Delimiter, @Value, 1 + EndIndex)
                        FROM 
                            cte
                        WHERE
                            EndIndex > 0
                    )
                    SELECT
                        Idx,
                        SubString(@Value, StartIndex, CASE
                            WHEN EndIndex > 0 THEN EndIndex - StartIndex
                            ELSE LEN(@Value)
                        END) As Value
                    FROM
                        cte
                    

                    );
                    GO

                    Then you can build a single query:

                    WITH ctePersonnelList (PersonnelBaseID) As
                    (
                    SELECT
                    CASE
                    WHEN Value Like '%[^0-9]%' THEN Null
                    ELSE CAST(Value As int)
                    END
                    FROM
                    dbo.fn_Split(@PersonnelList, ',')
                    WHERE
                    Value Not Like '%[^0-9]%'
                    ),
                    cteDates (PersonnelBaseID, StartDate, EndDate) As
                    (
                    SELECT
                    L.PersonnelBaseID,
                    Min([date]),
                    Max([date])
                    FROM
                    ctePersonnelList As L
                    INNER JOIN lfd_DailyStatistics As S
                    ON L.PersonnelBaseID = S.PersonnelBaseID
                    WHERE
                    [Year] = @WorkPeriodYear
                    And
                    WorkingPeriodID = @WorkPeriodID
                    GROUP BY
                    L.PersonnelBaseID
                    )
                    SELECT
                    A.*,
                    CAST(CASE WHEN Q.StartDate IS NULL THEN 0 ELSE 1 END AS bit) As NeedsRecalculation
                    FROM
                    cteDates As D
                    INNER JOIN lfd_dailyAbsence As A
                    ON A.PersonnelBaseID = D.PersonnelBaseID
                    And A.StartDate >= D.StartDate
                    And A.EndDate <= DateAdd(day, 1, D.EndDate)
                    LEFT JOIN lfd_CalculationQueue As Q
                    ON A.PersonnelBaseID = Q.PersonnelBaseID
                    And Q.StartDate <= D.EndDate
                    ORDER BY
                    A.PersonnelBaseID,
                    A.StartDate
                    ;


                    "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                    M Offline
                    M Offline
                    mhd sbt
                    wrote on last edited by
                    #9

                    thanks Richard this is a good solution

                    1 Reply Last reply
                    0
                    Reply
                    • Reply as topic
                    Log in to reply
                    • Oldest to Newest
                    • Newest to Oldest
                    • Most Votes


                    • Login

                    • Don't have an account? Register

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • World
                    • Users
                    • Groups