2009-02-17 37 views
5

Tôi có hai bảng trong một DB SQLite, INVITEM và SHOPITEM. Thuộc tính được chia sẻ của họ là ItemId và tôi muốn thực hiện INNER JOIN. Dưới đây là các truy vấn:"tên cột mơ hồ" trong SQLite INNER JOIN

SELECT INVITEM.CharId AS CharId, 
      INVITEM.ItemId AS ItemId 
     FROM (INVITEM as INVITEM 
INNER JOIN SHOPITEM AS SHOPITEM 
     ON SHOPITEM.ItemId = INVITEM.ItemId) 
    WHERE ItemId = 3; 

SQLite không thích nó:

SQL error: ambiguous column name: ItemId 

Các lỗi sẽ biến mất nếu tôi viết WHERE INVITEM.ItemId = 3, nhưng vì điều kiện WHERE là nhiều hay ít người dùng chỉ định, tôi khá chắc nó hoạt động mà không cần phải chỉ định bảng. NATURAL JOIN dường như giải quyết vấn đề, nhưng tôi không chắc liệu giải pháp đó có đủ chung hay không (ví dụ như tôi có thể sử dụng trong trường hợp này, nhưng tôi không chắc liệu mình có thể sử dụng trong mọi trường hợp) không?

Mọi SQL thay thế cú pháp nào có thể khắc phục được sự cố?

Trả lời

0

Tôi sẽ tránh xa việc cho phép người dùng viết mệnh đề SQL trực tiếp. Đây là nguồn của lỗ hổng SQL Injection.

Nếu bạn cần truy vấn linh hoạt, hãy thử phân tích cú pháp đầu vào của người dùng và thêm mệnh đề where thích hợp.

Dưới đây là một số mã C# để hiển thị các ý tưởng chung

// from user input 
string user_column = "ItemID"; 
string user_value = "3"; 

string sql = "SELECT INVITEM.CharId AS CharId, INVITEM.ItemId AS ItemId FROM (INVITEM as INVITEM INNER JOIN SHOPITEM AS SHOPITEM ON SHOPITEM.ItemId = INVITEM.ItemId) "; 

if (user_column == "ItemID") 
{ 
    // using Int32.Parse here to prevent rubbish like "0 OR 1=1; --" being entered. 
    sql += string.Format("WHERE INVITEM.ItemID={0}",Int32.Parse(user_value)); 
} 

Rõ ràng nếu bạn đang làm việc với nhiều hơn một khoản, bạn sẽ phải thay VÀ cho WHERE tại các khoản sau này.

+0

Tôi đã làm một việc như thế này. Tôi không bao giờ cho phép người dùng viết SQL trực tiếp, nhưng các mệnh đề WHERE được xây dựng bằng cách sử dụng các mẫu biểu thức. Đủ điều kiện các tên cột khi cần thiết là đủ. – ggambett

0

Chỉ cần thay đổi bí danh cột của bạn thành một cái gì đó tương tự, nhưng độc đáo (chẳng hạn như ITEM_ID).

10

Tôi sẽ viết truy vấn này theo cách này:

SELECT i.CharId AS CharId, i.ItemId AS ItemId 
FROM INVITEM as i INNER JOIN SHOPITEM AS s USING (ItemId) 
WHERE i.ItemId = 3; 

Tôi đang sử dụng cú pháp USING (ItemId) mà chỉ là một vấn đề của hương vị. Nó tương đương với ON (i.ItemID = s.ItemID).

Nhưng tôi đã giải quyết sự mơ hồ bằng cách đủ điều kiện i.ItemID trong mệnh đề WHERE. Bạn sẽ nghĩ rằng điều này là không cần thiết, kể từ i.ItemID = s.ItemID. Cả hai đều bằng nhau bởi tính tương giao, vì vậy không có sự mơ hồ ngữ nghĩa. Nhưng dường như SQLite không đủ thông minh để biết điều đó.

Tôi không thích sử dụng NATURAL JOIN. Nó tương đương với tham gia equi của mỗi cột tồn tại trong cả hai bảng có cùng tên. Tôi không thích sử dụng điều này bởi vì tôi không muốn nó so sánh các cột mà tôi không muốn nó, đơn giản chỉ vì chúng có cùng tên.