skip to Main Content

I have two tables contacts and calllist. contacts has multiple columns containing phone numbers. calllist has only one column from_number containing phone numbers. I’m trying to get all phone numbers from the column from_number which do not match the phone numbers in the table calllist.

Here is my working but probably very inefficient and slow SQL query:

SELECT from_number AS phone_number, COUNT(from_number) AS number_of_calls
FROM calllist
WHERE from_number NOT IN (
    SELECT businessPhone1
    FROM contacts
    WHERE businessPhone1 IS NOT NULL
)
AND from_number NOT IN (
    SELECT businessPhone2
    FROM contacts
    WHERE businessPhone2 IS NOT NULL
)
AND from_number NOT IN (
    SELECT homePhone1
    FROM contacts
    WHERE homePhone1 IS NOT NULL
)
AND from_number NOT IN (
    SELECT homePhone2
    FROM contacts
    WHERE homePhone2 IS NOT NULL
)
AND from_number NOT IN (
    SELECT mobilePhone
    FROM contacts
    WHERE mobilePhone IS NOT NULL
)
AND (received_at BETWEEN '$startDate' AND DATE_ADD('$endDate', INTERVAL 1 DAY))
GROUP BY phone_number
ORDER BY number_of_calls DESC
LIMIT 10

How do i rewrite this SQL query to be faster? Any help would be much appreciated.

2

Answers


  1. try this

        SELECT from_number AS phone_number, COUNT(from_number) AS number_of_calls
        FROM calllist
        WHERE from_number NOT IN (
            SELECT businessPhone1
            FROM contacts
            WHERE businessPhone1 IS NOT NULL
    UNION
    SELECT businessPhone2
            FROM contacts
            WHERE businessPhone2 IS NOT NULL
    UNION
    SELECT homePhone1
            FROM contacts
            WHERE homePhone1 IS NOT NULL
    UNION
    SELECT homePhone2
            FROM contacts
            WHERE homePhone2 IS NOT NULL
    UNION
    SELECT mobilePhone
            FROM contacts
            WHERE mobilePhone IS NOT NULL
        )
        AND (received_at BETWEEN '$startDate' AND DATE_ADD('$endDate', INTERVAL 1 DAY))
        GROUP BY phone_number
        ORDER BY number_of_calls DESC
        LIMIT 10
    
    Login or Signup to reply.
  2. I don’t like the schema design. You have multiple columns holding ‘identical’ data — namely phone numbers. What if technology advances and you need a 6th phone number??

    Instead, have a separate table of phone numbers, with linkage (id) to JOIN back to calllist. That gets rid of all the slow NOT IN ( SELECT... ), avoids a messy UNION ALL, etc.

    If you desire, the new table could have a 3rd column that says which type of phone it is.

    ENUM('unknown', 'company', 'home', 'mobile')
    

    The simplified query goes something like

    SELECT cl.from_number AS phone_number,
           COUNT(*) AS number_of_calls
        FROM calllist AS cl
        LEFT JOIN phonenums AS pn  ON cl.id = pn.user_id
        WHERE cl.received_at >= '$startDate' AND
          AND cl.received_at  < '$endDate' + INTERVAL 1 DAY
          AND pn.number IS NULL  -- not found in phonenums
    GROUP BY phone_number
    ORDER BY number_of_calls DESC
    LIMIT 10
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search