Counting specific records from 2 different Tables

  • I have a Master Table MyTable

    MyTable
    Auto_IDNameDOB
    1Shamshad04-Feb-74
    2Zulfiqar05-Jul-77
    3Talha15-May-82
    4Waqar13-May-75
    5Nadeem15-Dec-80

    I have two Child Tables:

    LibraryChannel
    Auto_IDNameCompletedAuto_IDNameCompleted
    1Shamshad01Shamshad1
    2Shamshad12Waqar1
    3Shamshad13Shamshad1
    4Zulfiqar04Waqar0
    5Zulfiqar05Talha0
    6Shamshad1

    The relationship key is [Name], I need the Following result:

    Result
    NameDOBTot. Library VisitsCompletedTot. Channel VisitsCompleted
    Shamshad04-Feb-744322
    Zulfiqar05-Jul-772000
    Talha15-May-820010
    Waqar13-May-750021
    Nadeem15-Dec-800000

    I'm using following query:

    select MyList.[Name],

    Count(case when Library.Auto_ID>=1 then 1 else NULL end) [Total in Library],

    Count(case Library.completed when 1 then Library.completed else NULL end) as LibraryCompleted

    from MyList inner join Library on MyList.Name = Library.Name

    group by MyList.[Name]

     

    UNION

     

    select MyList.[Name],

    Count(case when Channel.Auto_ID>=1 then 1 else NULL end) [Total in Channel],

    Count(case Channel.completed when 1 then Channel.completed else NULL end) as ChanneCompleted

    from MyList inner join Channel on MyList.Name = Channel.Name

    group by MyList.[Name]

     

    This query is producing something different but again we need to put grouping on [Name] and keep columns separate to retrieve the output like I require above. I can also put date as parameter to see only those [Name] who's DOB year between 1974 AND 1980.

     

    I want to run one single query to get output. Is it possible, how. Plz. help.

     

     

    Shamshad Ali.

     

     

  • Try a single select with outer joins to MyTable...

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • There is the sql:

    SELECT     MyList.[Name], MyList.DOB,

    Count(Library.[Name]) as [Total in Library],Sum(Library.Completed) as [LibraryCompleted],

    Count(Channel.[Name]) as [Total in Channel],Sum(Channel.Completed) as [ChannelCompleted]

    FROM         MyList  LEFT OUTER JOIN

                          Library ON MyList.[Name] = Library.[Name]

       LEFT OUTER JOIN

                          Channel ON MyList.[Name] = Channel.[Name]

    group by MyList.Name,MyList.DOB

     

    Good luck!

    In Theory, theory and practice are the same...In practice, they are not.
  • Sorry, it works logically, but it produces wrong resultset. I have tested it before my submission here. Better if someone faced this situation and solved it in a single query solving performance issue too, can reply.

     

    I suggest you make these three tables in a test database and see results.

    Anyway thanks for you all and help.

     

     

    Shamshad Ali.

  • Here is my query result if I use left outer join:

    select MyList.[Name], convert(varchar, DOB, 107) as DOB,

    Count(case when Library.Auto_ID>=1 then 1 else NULL end) [Total in Library],

    Count(case Library.completed when 1 then Library.completed else NULL end) as LibraryCompleted,

    Count(case when Channel.Auto_ID>=1 then 1 else NULL end) [Total in Channel],

    Count(case Channel.completed when 1 then Channel.completed else NULL end) as ChanneCompleted

    from MyList left outer join Library on MyList.Name = Library.Name

    left outer join Channel on MyList.Name = Channel.Name

    --where Year(MyList.DOB) between '1974' and '1980'

    group by MyList.[Name], MyList.DOB

    OUTPUT: (which is wrong)

    NameDOBTot. In LibraryLibrary com.Tot. in ChannelchannelComp
    Nadeem15-Dec-800000
    Shamshad4-Feb-748688
    Talha15-May-820010
    Waqar13-May-750021
    Zulfiqar5-Jul-772000
  • Shamshad, both Sorin and Jeff were absolutely correct. You need left joins. Your query didn't work because the aggregates in your query were incorrectly specified.

    This will help you: test data and the result you expect. Please note that the query is essentially the same as Sorin's (apart from ISNULL() to change NULL to zero).

     

    DROP TABLE #MyTable
    CREATE TABLE #MyTable (Auto_ID int, [Name] VARCHAR(10), DOB DATETIME) 
    INSERT INTO #MyTable (Auto_ID, [Name], DOB)
    SELECT 1, 'Shamshad', '04-Feb-74' UNION ALL 
    SELECT 2, 'Zulfiqar', '05-Jul-77' UNION ALL  
    SELECT 3, 'Talha', '15-May-82' UNION ALL  
    SELECT 4, 'Waqar', '13-May-75' UNION ALL  
    SELECT 5, 'Nadeem', '15-Dec-80' 
    --SELECT * FROM #MyTable -- sanity check
    DROP TABLE #Library
    CREATE TABLE #Library (Auto_ID int, [Name] VARCHAR(10), Completed tinyint)   
    INSERT INTO #Library (Auto_ID, Name, Completed)
    SELECT 1, 'Shamshad', 0 UNION ALL
    SELECT 2, 'Shamshad', 1 UNION ALL  
    SELECT 3, 'Shamshad', 1 UNION ALL  
    SELECT 4, 'Zulfiqar', 0 UNION ALL  
    SELECT 5, 'Zulfiqar', 0 UNION ALL  
    SELECT 6, 'Shamshad', 1 
    --SELECT * FROM #Library -- sanity check
    DROP TABLE #Channel
    CREATE TABLE #Channel (Auto_ID int, [Name] VARCHAR(10), Completed tinyint)
    INSERT INTO #Channel (Auto_ID, Name, Completed)
    SELECT 1, 'Shamshad', 1 UNION ALL 
    SELECT 2, 'Waqar', 1 UNION ALL 
    SELECT 3, 'Shamshad', 1 UNION ALL 
    SELECT 4, 'Waqar', 0 UNION ALL 
    SELECT 5, 'Talha', 0 
    --SELECT * FROM #Channel -- sanity check
    -- run query
    SELECT m.[Name], m.DOB, 
     ISNULL(l.[Tot. Library Visits], 0), ISNULL(l.Completed, 0), 
     ISNULL(c.[Tot. Channel Visits], 0), ISNULL(c.Completed, 0)
    FROM #MyTable m
    LEFT JOIN (SELECT [Name], COUNT([Name]) AS [Tot. Library Visits], SUM(Completed) AS Completed
     FROM #Library 
     GROUP BY [Name]) l 
      ON l.[Name] = m.[Name]
    LEFT JOIN (SELECT [Name], COUNT([Name]) AS [Tot. Channel Visits], SUM(Completed) AS Completed
     FROM #Channel 
     GROUP BY [Name]) c 
      ON c.[Name] = m.[Name]

     

    Cheers

    ChrisM

     

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • Hi Ali,

     

    I have tested my query against a test database with exactly your data tables and it works well. As Chris said, I should replace NULL values with zeroes, but this is your choice.

     

    Have a good day,

    Sorin

    In Theory, theory and practice are the same...In practice, they are not.
  • Thanks all for your great help, I have implemented and test it on my real data where I have been assigned to improve performance and the result should be same as it is working (developed by previous DBA). From above scenario, I have to exclude those if no one has visited library or any channel. like in above table "Nadeem" is the guy who has no entry in Library or Channel. how can i exclude it. I tried to use INNER Join in both library and Channel that is giving me only records that has entries in both like "Shamshad" is the only record who has entries in both tables.

    SELECT m.[Name], m.DOB, 

    ISNULL(l.[Tot. Library Visits], 0),

    ISNULL(l.Completed, 0), 

    ISNULL(c.[Tot. Channel Visits], 0),

    ISNULL(c.Completed, 0)

    FROM #MyTable m

    inner JOIN

    (

    SELECT [Name], COUNT([Name]) AS [Tot. Library Visits],

    SUM(Completed) AS Completed FROM #Library  GROUP BY [Name]

    ) l   ON l.[Name] = m.[Name]

    inner JOIN

    (SELECT [Name], COUNT([Name]) AS [Tot. Channel Visits],

    SUM(Completed) AS Completed FROM #Channel  GROUP BY [Name]) c   ON c.[Name] = m.[Name]

     

    OUTPUT:

    NameDOBTot.Lib. VisitLib comp.Tot. Channel visitchannel comp.
    Shamshad4-Feb-744322

    Required:

    NameDOBTot.Lib. VisitLib comp.Tot. Channel visitchannel comp.Required or NOT
    Shamshad4-Feb-744322required
    Zulfiqar7/5/19772000required
    Talha5/15/19820010required
    Waqar5/13/19750021required
    Nadeem12/15/19800000No need.  X

    Shamshad Ali

  • -- run query
    SELECT m.[Name], m.DOB,  
    ISNULL(l.[Tot. Library Visits], 0), 
    ISNULL(l.Completed, 0),  
    ISNULL(c.[Tot. Channel Visits], 0), 
    ISNULL(c.Completed, 0)
    FROM #MyTable m
    LEFT JOIN (SELECT [Name], COUNT([Name]) AS [Tot. Library Visits], SUM(Completed) AS Completed 
     FROM #Library  
     GROUP BY [Name]) l   ON l.[Name] = m.[Name]
    LEFT JOIN (SELECT [Name], COUNT([Name]) AS [Tot. Channel Visits], SUM(Completed) AS Completed 
     FROM #Channel  
     GROUP BY [Name]) c   ON c.[Name] = m.[Name]
    WHERE (l.[Name] IS NOT NULL OR c.[Name] IS NOT NULL)
    Cheers
    ChrisM
    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • Thanks for the help. I have implemented and it works perfect. By keeping same scenario furthermore, I require to input DOB @FromDate and @ToDate and @FirstName and @LastName as Parameter passed to this query, we have only [Name] field in MyTable. Which is combination of FirstName and LastName. we are using these parameters from Front-end. If these parameters are supplied otherwise it won't use any WHERE in TOP of the query, this is only when user input parameters otherwise it assumes there is no paramter supplied like following code:

    Declare

     @ToDate datetime,

     @FromDate datetime,

     @LastName varchar(100) ,                           

     @FirstName varchar(100)

     

     

    SELECT m.[Name], m.DOB, 

    ISNULL(l.[Tot. Library Visits], 0),

    ISNULL(l.Completed, 0), 

    ISNULL(c.[Tot. Channel Visits], 0),

    ISNULL(c.Completed, 0)

    FROM #MyTable m

    left JOIN

    (

    SELECT [Name], COUNT([Name]) AS [Tot. Library Visits],

    SUM(Completed) AS Completed FROM #Library  GROUP BY [Name]

    ) l   ON l.[Name] = m.[Name]

    left JOIN

    (SELECT [Name], COUNT([Name]) AS [Tot. Channel Visits],

    SUM(Completed) AS Completed FROM #Channel  GROUP BY [Name]) c   ON c.[Name] = m.[Name]

    WHERE (l.[Name] IS NOT NULL OR c.[Name] IS NOT NULL)

    AND  m.[Name] LIKE  @FirstName + '%_' AND m.[Name] LIKE '_%'+ @LastName

     

    Here it won't work untill I set parameters with check condition like

     

    IF @FirstName is null

    set @FirstName = ''

    IF @LastName is null

    set @LastName = ''

     

     

    If @FirstName is Null then I have use set it Empty  like ''. Is there any good solution that may produce beter peformance and less code ? so that I can reduce if conditions

     

     

    Shamshad Ali.

  • This will work...

    .

    .

    WHERE (l.[Name] IS NOT NULL OR c.[Name] IS NOT NULL)

    AND  m.[Name] LIKE 

        CASE WHEN @FirstName IS NULL

             THEN m.[Name]

             ELSE @FirstName + '%_'

        END

    .

    .

     

     

    ...but it's inelegant and probably inefficient. I would suggest you set up the original query as a derived table then apply the new filters to a SELECT into that derived table.

    you might also get some mileage out of concatenating @FirstName and @lastname:

    SET @fullname = RTRIM(@FirstName) + '_' + RTRIM(@LastName)

    Try it out, repost if you get stuck.

    Cheers

    ChrisM

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

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

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