简体   繁体   中英

SQL: table contains individual items and FK to lists - return all individual items from table & lists

I have a table that combines:

  • Conditions for auto-emails (FK to table with auto-email UI action triggers)
  • Emails for individual users (FK to table with emails)
  • Mailing lists (FK to table with mailing lists)

This table allows me to:

  • Add individual emails to auto-email triggers
  • Add individual emails to mailing lists
  • Add mailing lists to auto-email triggers
    • Mailing lists only have individual emails - mailing lists cannot be nested

When I need to send an email from the website, I need to pull all distinct emails for the desired auto-email trigger. I want individual emails only . For any/all mailing lists assigned to the trigger, I want to return the emails for that mailing list, not the name of the mailing list.

EDIT (updated tables):

Actual DB tables:

User table

User_ID   First_Name   Last_Name   Email        Other Info (multiple columns)
----------------------------------------------------------------------------
1         Mike         Smith       mike@me.com   <other info>
2         Sue          Jones       sue@me.com    <other info>
3         Bob          Roberts     bob@me.com    <other info>
4         Mary         Evans       mary@me.com   <other info>
5         Joe          Miller      joe@me.com    <other info>

Auto_Email table

Auto_Email_ID   Page      Trigger
----------------------------------------------------------------------------
1               Events    Save Event
2               Events    Edit Event
3               Events    Delete Event
4               Friends   Request Friend
5               Friends   Confirm Friend

Mailing_List table

Mailing_List_ID   Mailing_List
----------------------------------------------------------------------------
1                 Team A
2                 Team B
3                 Team C

Email_List table

ID   Auto_Email_ID   User_ID    List_ID
----------------------------------------------------------------------------
1    1               1          NULL
2    1               NULL       1
3    1               NULL       2
4    2               2          NULL
5    2               NULL       3
6    NULL            1          1
7    NULL            3          1
8    NULL            4          2
9    NULL            5          3

Email_List view

ID   Auto_Email_ID   Trigger         User_ID   Email         List_ID   List
----------------------------------------------------------------------------
1    1               Save Event      1         mike@me.com   NULL      NULL
2    1               Save Event      NULL      NULL          1         Team A
3    1               Save Event      NULL      NULL          2         Team B
4    2               Confirm Friend  2         sue@me.com    NULL      NULL
5    2               Confirm Friend  NULL      NULL          3         Team C
6    NULL            NULL            1         mike@me.com   1         Team A
7    NULL            NULL            3         bob@me.com    1         Team A
8    NULL            NULL            4         mary@me.com   2         Team B
9    NULL            NULL            5         joe@me.com    3         Team C

Desired results for Auto_Email condition "Save Event": (from individual emails, Team A emails, and Team B emails):

mike@me.com
bob@me.com
mary@me.com

I know how to do this with the below code, but that's a lot of loops and calls back to SQL. I'd prefer to do this with a single SQL proc/query, but I don't know how.

Using vb.Net:

Dim sendTo = New List(Of String)

For Each email As MyObject In GetEmailsForAutoEmail("Save Event") 'calls SQL proc
    If (email.Email_ID.HasValue) Then
        sendTo.Add(email.Email)
    Else
        For Each mlEmail As MyObject In GetEmailsForMailingList(email.List) 'calls SQL proc
            sendTo.Add(mlEmail.Email)
        Next
    End If
Next

sendTo = sendTo.Distinct()

The following seems to do the job:

SELECT
  email
FROM Usr U
JOIN Email_List E
  ON U.user_ID = E.user_ID
  AND E.list_ID IS NULL
JOIN Auto_Email A
  ON E.auto_Email_ID = A.auto_Email_ID
  AND A.triggr = 'Save Event'
UNION
SELECT
  email
FROM Usr U
JOIN Email_List E1
  ON U.user_ID = E1.user_ID
  AND E1.auto_Email_ID IS NULL
JOIN Email_List E2
  ON E1.list_ID = E2.list_ID
  AND E1.auto_Email_ID IS NULL
  AND E2.user_ID IS NULL
JOIN Mailing_List M
  ON E2.list_ID = M.mailing_List_ID
  AND E2.user_ID IS NULL
JOIN Auto_Email A
  ON E2.auto_Email_ID = A.auto_Email_ID
  AND E2.user_ID IS NULL
  AND A.triggr = 'Save Event'
;

It UNION s the individually listed users with the users, signed up via some list(s).

See it in action: SQL Fiddle .

For simpler SQL / better readability (and possibly slightly better performance), the Email_List table would probably better be split into two or three tables:

  • User_List matching users and lists, and
  • one (each) for users and lists to align to Auto_Email .

Please comment, if and as this requires adjustment / further detail.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM