2013-04-04 24 views
5

Tôi có câu lệnh SQL sau:chèn một chuỗi để một tuyên bố chuẩn bị mà không cần ''

Select i.imageID, theImage, translationRating 
From images i 
inner join translationchains t 
on t.imageId = i.imageid 
where i.userID=(someUserID) And i.translated =0 
and t.targetLang in (select targetLang from translationChains) 

tôi muốn làm cho nó một tuyên bố chuẩn bị để sử dụng trong mã java của tôi:

Select i.imageID, theImage, translationRating 
From images i 
inner join translationchains t 
on t.imageId = i.imageid 
where i.userID=? And i.translated =0 
and t.targetLang in (select ? from translationChains) 

sự đầu vào cho đầu tiên? là một Id người dùng (số nguyên) và nó hoạt động tốt.

đầu vào thứ hai là một chuỗi mà chứa một languageId - đó là một chuỗi mà một trong hai chứa một số đại diện cho một ngôn ngữ, hoặc chuỗi "targetLang" đó là tên của cột (= tất cả langs)

trong mã java của tôi, tôi đã làm như sau:

Image.setInt(1, userID); 
Image.setString(2, langID); 
Image.executeQuery() 

vấn đề của tôi là khi tôi gửi chuỗi "targetLang" như tham số thứ hai tuyên bố chuẩn bị được chèn nó như 'targetLang' (với 'trước và sau '), với các con số không phải là một vấn đề beacuse 3 =' 3 ', nhưng với chuỗi nó cho tôi kết quả khác nhau từ những gì tôi cần - Tôi luôn nhận được một tập kết quả trống vì không có gì bằng 'targetLang'. Tôi cần phải chèn chuỗi này vào câu lệnh đã chuẩn bị mà không có '. là nó có thể hoặc tôi cần phải sử dụng một cái gì đó khác với tuyên bố chuẩn bị?

Tôi biết tôi có thể xây dựng một chuỗi có chứa tất cả các truy vấn này nhưng tôi đang tìm kiếm cái gì thanh lịch hơn tnx


chỉnh sửa:

Đây là Tạo translationChains bảng:

Create Table if not exists TranslationChains (
    ImageID int (10) NOT NULL, 
    SourceLang int NOT NULL, 
    TargetLang int NOT NULL, 
    Translated tinyint default 0, 
    Translation text, 
    Translator varchar (30), 
    CONSTRAINT translate_image PRIMARY KEY (ImageID,SourceLang, TargetLang), 
    FOREIGN KEY (ImageID) REFERENCES Images(ImageID) ON DELETE CASCADE, 
    FOREIGN KEY (SourceLang) REFERENCES Languages(languageID) ON DELETE CASCADE, 
    FOREIGN KEY (TargetLang) REFERENCES Languages(languageID) ON DELETE CASCADE) 

Như bạn thấy, tôi đang cố gắng chụp ảnh theo cột "targetLang" ich là một cột int. Mỗi số đại diện cho một ngôn ngữ.

Bây giờ tôi có hai lựa chọn trong việc lựa chọn hình ảnh từ bảng:

  • Chọn một ngôn ngữ cụ thể, ví dụ: đưa ra một số như là đầu vào thứ hai.
  • Chọn tất cả ngôn ngữ, tức là đặt đầu vào thứ hai thành tên cột "targetLang".

Vì vậy, tôi không so sánh với chuỗi cố định "targetLang". Tôi muốn chọn tất cả các giá trị có thể cho cột này (chọn targetLang từ translationChains).

Trả lời

3

Tham số truy vấn chỉ có thể thay thế giá trị bằng chữ - nghĩa là nơi bạn thường đặt một chuỗi ký tự được trích dẫn, một ngày tháng được trích dẫn hoặc một chữ số. Do đó, giá trị chuỗi sẽ luôn là được hiểu là chuỗi ký tự, như thể bạn đã đặt nó vào truy vấn với dấu nháy đơn.

Đối với tên cột, tên bảng, biểu thức SQL, từ khóa SQL, v.v ..., bạn phải nội suy các giá trị này vào truy vấn SQL trước cuộc gọi chuẩn bị().

Để an toàn nhất, hãy sử dụng danh sách trắng để đầu vào của người dùng không bao giờ được nội suy vào các truy vấn SQL nguyên văn. Luôn xác thực đầu vào của người dùng (hoặc bất kỳ nội dung nào khác) trước khi sử dụng nó trong một truy vấn.

Tôi có written many examples danh sách trắng khi xây dựng truy vấn SQL.

Bạn cũng có thể xem các ví dụ trong bản trình bày SQL Injection Myths and Fallacies và sách của tôi SQL Antipatterns: Avoiding the Pitfalls of Database Programming.


Re bình luận của bạn:

Tôi không chắc chắn chính xác những gì bạn đang làm. Có vẻ như bạn muốn t.targetLang bằng một số chữ hoặc một chuỗi cố định 'targetLang'. Nếu như vậy, tôi không biết tại sao bạn đang làm một subquery ở tất cả - bạn chỉ nên sử dụng một tham số truy vấn cho một giá trị:

where i.userID = ? And i.translated = 0 
and t.targetLang = ? 

Image.setString(2, langID); // either '3' or 'targetLang' 

Nhưng tôi không chắc là tôi hiểu mô tả của bạn đầy đủ. Số liệu có biểu thị vị trí của cột bạn muốn so sánh không? Trên cùng hàng với t.targetLang? Nếu vậy, tôi vẫn không nghĩ rằng bạn cần một truy vấn phụ. Bạn có thể sử dụng một biểu thức như sau:

where i.userID = ? And i.translated = 0 
and FIELD(t.targetLang, t.targetLang, t.column2, t.column3, t.column4) = ? 

Image.setString(2, '1'); // for the case where you allow all langs 
Image.setString(2, '3'); // for the case where you want to match a specific column. 

Xem hướng dẫn trên FIELD() chức năng trong MySQL, những tìm kiếm cho các đối số đầu tiên trong một danh sách các biểu thức. Nó trả về vị trí số nguyên của trường khớp.

Sử dụng phương pháp này, bạn chuyển vị trí bạn muốn t.targetLang của bạn khớp, và điều này cho phép bạn chuyển phần động dưới dạng giá trị, thay vì làm tên cột. Nó cũng cho phép bạn tránh truy vấn phụ.

Nếu tôi vẫn sai và không hiểu vấn đề của bạn, vui lòng chỉnh sửa câu hỏi ban đầu của bạn và cung cấp thêm chi tiết. SHOW CREATE TABLE translationChains sẽ hữu ích. Ngoài ra, bạn có thể trả lời một số điều tôi phải đưa ra giả định, ví dụ: bạn đang cố gắng kết hợp t.targetLang với một giá trị trong một cột khác trên cùng một hàng?


Được rồi, giờ tôi hiểu mục tiêu của bạn tốt hơn. Dưới đây là một truy vấn mà làm những gì bạn muốn:

CHỌN i.imageID, theImage, translationRating TỪ Images i INNER JOIN TranslationChains t ON t.imageId = i.imageid ĐÂU i.userID =? VÀ i.translated = 0 VÀ? IN (t.targetLang, 'targetLang')

Bạn có thể chuyển làm tham số thứ hai hoặc một số nguyên để khớp với t.targetLang, nếu không chuỗi ký tự 'targetLang' sẽ khớp với giá trị 'targetLang 'trong vị ngữ. Tuy nhiên, tôi không thể đề xuất giải pháp này vì nó có thể sẽ không sử dụng chỉ mục rất tốt, nó có thể phải thực hiện chuyển đổi loại bằng cách so sánh tham số chuỗi với cột số nguyên.

Phương pháp hay hơn khi bạn muốn khớp với tất cả ngôn ngữ là thực hiện truy vấn mà không cần thuật ngữ cuối cùng trong mệnh đề WHERE.Tức là, trong ứng dụng của bạn, hãy thêm cụm từ đó có điều kiện, chỉ khi bạn muốn truy vấn tìm nạp một ngôn ngữ cụ thể. Nếu không, hãy bỏ qua cụm từ đó và bỏ qua Image.setString().

String sql = "SELECT i.imageID, theImage, translationRating 
FROM Images i 
INNER JOIN TranslationChains t 
    ON t.imageId = i.imageid 
WHERE i.userID = ? AND i.translated = 0 "; 

if (langId) { 
    sql += " AND ? IN (t.targetLang, 'targetLang')"; 
} 

. . . 

Image.setInt(1, userID); 
if (langId) { 
    Image.setString(2, langID); 
} 
Image.executeQuery() 
+0

tnx, nhưng bạn có thể làm rõ câu trả lời cho tôi không? Tôi không biết phải làm gì. Tôi sử dụng danh sách trắng = Tôi đang kiểm tra đầu vào của người dùng và sau đó quyết định nội dung cần chèn vào truy vấn, nhưng tôi không chắc chắn cách chèn nó với sự cố ở trên –

+0

đã chỉnh sửa bài đăng gốc –

+1

tnx! truy vấn này đang hoạt động: CHỌN i.imageID, theImage, translationRating FROM Images i INNER JOIN TranslationChains t ON t.imageId = i.imageid WHERE i.userID =? AND i.translated = 0 AND? IN (t.targetLang, 'targetLang') –

0

Bạn có thể thay đổi:

và t.targetLang trong (chọn từ translationChains?)

Để:

and (
     (
      ? = 'targetLang' and 
      t.targetLang in (
            select 
             targetLang 
            from 
             translationChains 
          ) 
     ) 
     or 
     ? = t.targetLang 
    ) 

và làm setString (3, langId), tức là tạo tham số thứ 3 giống như tham số thứ 2. Không có cách nào, điều này là thanh lịch hơn hoặc hiệu quả hơn trong kiến ​​thức của tôi, nhưng cái gì đó sẽ làm việc!

Các vấn đề liên quan