2

Running a custom wordpress table to store notices to display to each individual site, I then store the dismissed notices as an option in the site's options table as a list (ie. 3,9,28,22)

Then, when loading the site I need to retrieve the site's notices excluding the ones already dismissed.

SELECT 
    *
FROM
    be_notices as notice
WHERE
    notice.id NOT IN ( SELECT option_value FROM wp_26_options WHERE option_name = 'be_dismissed_notices' )

The problem being it retrieves all the notices as expected, but excludes only the first number/id in the comma-separated list. If I put NOT IN (3,8) hardcoded it works. But that's exactly the value found in option_value so I am confused.

Any idea why it only excludes the first ID and not the second/other one(s)?

enter image description here

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
Lazhar
  • 1,401
  • 16
  • 37

2 Answers2

1

I used FIND_IN_SET = 0 instead.

WHERE ( FIND_IN_SET( notice.id, ( SELECT option_value FROM $table_options WHERE option_name = 'be_dismissed_notices' ) ) = 0 )
Lazhar
  • 1,401
  • 16
  • 37
1

Solution 1 - antijoin (excluding LEFT JOIN):

SELECT notice.*
FROM be_notices as notice
LEFT JOIN wp_26_options as opt
    ON  opt.option_name = 'be_dismissed_notices'
    AND FIND_IN_SET(notice.id, opt.option_value)
WHERE opt.id IS NULL

Solution 2 - NOT EXISTS:

SELECT notice.*
FROM be_notices as notice
WHERE NOT EXISTS (
    SELECT 1
    FROM wp_26_options as opt
    WHERE opt.option_name = 'be_dismissed_notices'
      AND FIND_IN_SET(notice.id, opt.option_value)
)

NOTE that a search with FIND_IN_SET() can not use an index and you will allways end up with a full table/index scan. Normalizing your tables might be a better solution.

Paul Spiegel
  • 30,925
  • 5
  • 44
  • 53