0

I want to mark unused datasets in MySQL from a list in python. How can a list be created in python that will serve the MySQL query?

Here is my approach:

The following python list contains urls

item['media_urls'] = [
    {'type': 'image', 'url': 'p1.jpg'}, 
    {'type': 'image', 'url': 'p2.jpg'}
]

Create array of available urls. This code does not work as I believe the var needs to be initialised in the beginning and then the comma should not be after the last value:

for media_url in item['media_urls']:
    found_media += media_url['url'].', '

I also tried:

found_media = ','.join(media_url['url'])
# results in: TypeError: list indices must be integers or slices, not str

Update table and set all urls that are not in found_media to "disabled":

# pseudo code, I just need the query
$sql = "
    UPDATE tbl
    SET status = 'disabled'
    WHERE URL NOT IN ($found_media)
"

Any help on this is greatly appreciated.

2
  • Join your URLs list into one CSV string (no space after comma !) then use WHERE !FIND_IN_SET(URL, $found_media). Remember - this forbids index usage. Commented Mar 16, 2021 at 7:40
  • That sounds about right, I am struggling with creating this CSV string from the python list. Commented Mar 16, 2021 at 7:40

3 Answers 3

2

You should really use a prepared query with parameters for the URL values to protect against SQL injection. Use a list comprehension to find all the found_media values, then use join to generate a parameter list for the query and then finally execute the query:

item = {'media_urls': [
    {'type': 'image', 'url': 'p1.jpg'}, 
    {'type': 'image', 'url': 'p2.jpg'}
]}

found_media = [m['url'] for m in item['media_urls']]
params = ','.join(['%s'] * len(found_media))

sql = f'''
UPDATE tbl
SET status = 'disabled'
WHERE URL NOT IN ({params})
'''

cursor.execute(sql, tuple(found_media))
Sign up to request clarification or add additional context in comments.

5 Comments

This is the right answer irregardless of what op asked for :-)
@AllanWind yeah, I've just taken it to its logical conclusion which is to do what is asked in the first sentence rather than the title.
@AllanWind That looks promissing. I am trying to follow your advise on prepared queries. How would that look like if I need to pass more values to the statement? E.g.: UPDATE tbl SET STATUS = 'unused', DATE_EDITED = curdate() WHERE merchant_id = 2 AND SKU = '09633907' AND STATUS != 'unused' AND URL NOT IN ({params})
@merlin if you want to pass the merchant_id and SKU values as well, just replace the fixed values in the query with %s, and use tuple([2, '09633907'] + found_media) for the parameters (obviously you can replace those values with variables if required).
Thank you @AllanWind. That also helped me to understand how to use prepared queries.
1

Define item. Use map to extract each url, quote, then convert that array to a comma separated string with join:

item = {
    'media_urls': [
            {'type': 'image', 'url': 'p1.jpg'}, 
            {'type': 'image', 'url': 'p2.jpg'}
    ]
}
found_media = ','.join(map(lambda u: "'%s'" % u['url'], item['media_urls']))
print(found_media)

which will print:

'p1.jpg','p2.jpg'

1 Comment

This is clean, and correctly applies quotes around the strings which would be required for a query.
1

Yes, the object needs to be initialized for first case as you observed and there will be extra , as well in the end:

found_media = ""
for media_url  in item['media_urls']:
    found_media += media_url['url'] + ', '

You can use list comprehension with join() as:

found_media = ','.join([f"'{elt['url']}'" for elt in item['media_urls']])

4 Comments

I am pretty sure you need to quote the strings to be useful in the query.
the answer has clearly mentioned: there will be extra , as well in the end, I just wanted to point the flaw in the OPs script instead of just providing a different code. Regarding the quoting part, I think you are right but it is not clear from the question and the code presented so I didn't add anything that is not explicitly mentioned in the question.
Yes, I realized that after I wrote the initial comment, and subsequently revised comment.
@AllanWind you are absolutely right, the strings would need to be in quotes to be used in the query as is.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.