Tôi có một danh sách trăn, nói l
l = [1,5,8]
Tôi muốn viết một truy vấn sql để lấy dữ liệu cho tất cả các phần tử của danh sách, giả sử
select name from students where id = |IN THE LIST l|
Làm cách nào để thực hiện được điều này?
Tôi có một danh sách trăn, nói l
l = [1,5,8]
Tôi muốn viết một truy vấn sql để lấy dữ liệu cho tất cả các phần tử của danh sách, giả sử
select name from students where id = |IN THE LIST l|
Làm cách nào để thực hiện được điều này?
Câu trả lời:
Các câu trả lời cho đến nay đã được tạo mẫu các giá trị thành một chuỗi SQL thuần túy. Điều đó hoàn toàn tốt cho các số nguyên, nhưng nếu chúng tôi muốn làm điều đó cho các chuỗi, chúng tôi gặp sự cố thoát.
Đây là một biến thể sử dụng truy vấn được tham số hóa sẽ hoạt động cho cả hai:
placeholder= '?' # For SQLite. See DBAPI paramstyle.
placeholders= ', '.join(placeholder for unused in l)
query= 'SELECT name FROM students WHERE id IN (%s)' % placeholders
cursor.execute(query, l)
([placeholder]*len(l))
ở trong trường hợp chung vì trình giữ chỗ có thể gồm nhiều ký tự.
cursor.execute(f'SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})', l)
. @bobince, bạn cũng nên lưu ý trong giải pháp của mình rằng sử dụng ?
là cách an toàn để tránh tiêm SQL. Có rất nhiều câu trả lời ở đây dễ bị tấn công, về cơ bản là bất kỳ câu trả lời nào nối các chuỗi trong python.
Cách dễ nhất là chuyển danh sách thành tuple
đầu tiên
t = tuple(l)
query = "select name from studens where id IN {}".format(t)
Đừng làm phức tạp nó, Giải pháp cho điều này rất đơn giản.
l = [1,5,8]
l = tuple(l)
params = {'l': l}
cursor.execute('SELECT * FROM table where id in %(l)s',params)
Tôi hy vọng điều này đã giúp !!!
l
chỉ chứa một phần tử, bạn sẽ kết thúc với id IN (1,)
. Đó là một lỗi cú pháp.
sqlite3
. Thư viện nào bạn đã kiểm tra điều này chống lại?
SQL bạn muốn là
select name from studens where id in (1, 5, 8)
Nếu bạn muốn xây dựng điều này từ python, bạn có thể sử dụng
l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join(map(str, l)) + ')'
Hàm bản đồ sẽ biến đổi danh sách thành một danh sách các chuỗi có thể được gắn với nhau bằng dấu phẩy bằng cách sử dụng phương thức str.join .
Ngoài ra:
l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join((str(n) for n in l)) + ')'
nếu bạn thích biểu thức trình tạo hơn hàm bản đồ.
CẬP NHẬT: S. Lott đề cập trong các nhận xét rằng các liên kết SQLite trong Python không hỗ trợ trình tự. Trong trường hợp đó, bạn có thể muốn
select name from studens where id = 1 or id = 5 or id = 8
Tạo bởi
sql_query = 'select name from studens where ' + ' or '.join(('id = ' + str(n) for n in l))
string.join các giá trị danh sách được phân tách bằng dấu phẩy và sử dụng toán tử định dạng để tạo thành một chuỗi truy vấn.
myquery = "select name from studens where id in (%s)" % ",".join(map(str,mylist))
(Cảm ơn, blair-conrad )
%
được sử dụng ở đây chỉ là định dạng chuỗi Python đơn giản.
Tôi thích câu trả lời của bobince:
placeholder= '?' # For SQLite. See DBAPI paramstyle.
placeholders= ', '.join(placeholder for unused in l)
query= 'SELECT name FROM students WHERE id IN (%s)' % placeholders
cursor.execute(query, l)
Nhưng tôi nhận thấy điều này:
placeholders= ', '.join(placeholder for unused in l)
Có thể được thay thế bằng:
placeholders= ', '.join(placeholder*len(l))
Tôi thấy điều này trực tiếp hơn nếu ít thông minh hơn và ít chung chung hơn. Ở đây l
bắt buộc phải có độ dài (tức là tham chiếu đến một đối tượng xác định __len__
phương thức), điều này không thành vấn đề. Nhưng trình giữ chỗ cũng phải là một ký tự duy nhất. Để hỗ trợ việc sử dụng trình giữ chỗ nhiều ký tự:
placeholders= ', '.join([placeholder]*len(l))
Giải pháp cho câu trả lời @umounted, vì điều đó đã phá vỡ với bộ tuple một phần tử, vì (1,) không phải là SQL hợp lệ.:
>>> random_ids = [1234,123,54,56,57,58,78,91]
>>> cursor.execute("create table test (id)")
>>> for item in random_ids:
cursor.execute("insert into test values (%d)" % item)
>>> sublist = [56,57,58]
>>> cursor.execute("select id from test where id in %s" % str(tuple(sublist)).replace(',)',')'))
>>> a = cursor.fetchall()
>>> a
[(56,), (57,), (58,)]
Giải pháp khác cho chuỗi sql:
cursor.execute("select id from test where id in (%s)" % ('"'+'", "'.join(l)+'"'))
placeholders= ', '.join("'{"+str(i)+"}'" for i in range(len(l)))
query="select name from students where id (%s)"%placeholders
query=query.format(*l)
cursor.execute(query)
Điều này sẽ giải quyết vấn đề của bạn.
Nếu bạn đang sử dụng PostgreSQL với thư viện Psycopg2, bạn có thể cho phép bộ điều chỉnh bộ của nó thực hiện tất cả việc thoát và nội suy chuỗi cho bạn, ví dụ:
ids = [1,2,3]
cur.execute(
"SELECT * FROM foo WHERE id IN %s",
[tuple(ids)])
tức là chỉ cần đảm bảo rằng bạn đang truyền IN
tham số dưới dạng a tuple
. nếu đó là một, list
bạn có thể sử dụng = ANY
cú pháp mảng :
cur.execute(
"SELECT * FROM foo WHERE id = ANY (%s)",
[list(ids)])
lưu ý rằng cả hai sẽ được chuyển thành cùng một kế hoạch truy vấn, vì vậy bạn chỉ nên sử dụng cái nào dễ dàng hơn. ví dụ: nếu danh sách của bạn có trong một bộ, hãy sử dụng cái trước, nếu chúng được lưu trữ trong một danh sách, hãy sử dụng cái sau.
một giải pháp đơn giản hơn:
lst = [1,2,3,a,b,c]
query = f"""SELECT * FROM table WHERE IN {str(lst)[1:-1}"""
l = [1] # or [1,2,3]
query = "SELECT * FROM table WHERE id IN :l"
params = {'l' : tuple(l)}
cursor.execute(query, params)
Các :var
ký hiệu dường như đơn giản hơn. (Python 3.7)
Điều này sử dụng thay thế tham số và xử lý trường hợp danh sách giá trị đơn:
l = [1,5,8]
get_operator = lambda x: '=' if len(x) == 1 else 'IN'
get_value = lambda x: int(x[0]) if len(x) == 1 else x
query = 'SELECT * FROM table where id ' + get_operator(l) + ' %s'
cursor.execute(query, (get_value(l),))
','.join(placeholder * len(l))
sẽ ngắn hơn một chút trong khi vẫn có thể đọc được