'Sqlserver CTE how to get first non null value

I am trying to use the following query to get a user with his detail and any of his manager or manager's manager id who got a record in UserTag table.

I have got the partial result, but not sure how to get the first non null value. I have show my expected result below.

With Managers AS 
( 
--initialization 
SELECT Id, Email, ManagerID, NULL as UserID
FROM dbo.[User] 
WHERE email='[email protected]'
UNION ALL 
--recursive execution 
SELECT u.Id, u.Email, u.ManagerID, tb2.UserID
FROM dbo.[User] u 
    INNER JOIN Managers m ON m.ManagerID = u.ID
    OUTER apply (select userid from UserTag where userid = m.ManagerID and (TagID=9 or TagName = 'test')) tb2
) 
SELECT * FROM Managers 

enter image description here

Expected result:

enter image description here

Sample data and expected result:

User table
=========

Id      Email           ManagerID
---     -----           ---------
11813   [email protected]  1251
1251    [email protected]  302
302     [email protected]  1221
1221    [email protected]  358
358     [email protected]  988
988     [email protected]  NULL

100     [email protected] 101
101     [email protected] 102
102     [email protected] 103
103     [email protected] 104
104     [email protected] NULL

User Tag

Id  UserId      TagId       TagName
1   1221        9           test
2   104         9           test


Expected result
==============

UserId  Email               TagManagerId
------  -----               ------------
11813   [email protected]      1221
1251    [email protected]      1221
302     [email protected]      1221

Brief description: I have all users in User table. This is a self referencing table. I want to get all users whose immediate manager or manager's manager or any manager in his/hierarchy got a record in UserTag table with tagid=9 or tagname='test' as shown here.

Schema db<>fiddle here



Solution 1:[1]

Based on your Brief description, I believe that this is an XY Problem

  • There are solutions to the real need that don't include get first non null value.

What I believe you really need to do is find all the managers that are tagid=9 or tagname='test' and then recursively find all their subordinates. (Run the recursion in the opposite direction to your example query.)

The only complexity I can think of is that such a manager may have a subordinate that also meets those criteria, so I included a condition to avoid recursing them more than once.

WITH
  test9_managed_users AS
(
  SELECT
    u.*,
    u.managerid   AS closest_test9_manager_id,
    0             AS depth
  FROM
    [user]    AS u
  INNER JOIN
    UserTag   AS t
      ON  t.userid = u.managerid
      AND (t.TagID=9 or TagName = 'test')
  
  UNION ALL
  
  SELECT
    u.*,
    m.closest_test9_manager_id,
    m.depth+1
  FROM
    test9_managed_users   AS m
  INNER JOIN
    [user]                AS u
      ON u.managerid = m.id
  WHERE
    -- If a user is themselves a 'test9_manager', don't recurse their children
    -- > They would already have been included in the Anchor part of the CTE
    NOT EXISTS (
      SELECT *
        FROM UserTag  AS t
       WHERE t.userid = m.id
         AND (t.TagID=9 or TagName = 'test')
    )
)
SELECT
  *
FROM
  test9_managed_users
ORDER BY
  email

Demo with my own test data:


Demo with your test data:

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MatBailie