我有以下sql语句:

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)

我想使它成为准备在我的Java代码中使用的语句:
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)

输入的第一个?是一个用户ID(整数),并且工作正常。

第二个输入是一个包含languageId的字符串-它是一个包含表示语言的数字的字符串,或者是作为列名的字符串“targetLang”(=所有langs)

在我的Java代码中,我执行了以下操作:
Image.setInt(1, userID);
Image.setString(2, langID);
Image.executeQuery()

我的问题是当我发送字符串“targetLang”作为第二个参数时
准备好的语句将其插入为“targetLang”(带有“before and after”),带有数字,这不是问题,因为3 ='3',但是使用字符串,它给我的结果与我需要的结果不同-我总是得到一个结果集为空,因为没有东西等于“targetLang”。
我需要将此字符串插入到不带'的准备好的语句中。
是否可能,或者我需要使用与准备好的陈述不同的东西?

我知道我可以构建一个包含所有此查询的字符串,但是我正在寻找更优雅的东西
tnx

编辑:

这是创建表的翻译链:
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)

如您所见,我正在尝试根据int列的“targetLang”列来拍摄图像。每个数字代表一种语言。

现在,我有两个选择从该表中选择图像的选项:
  • 选择一种特定的语言,即输入数字作为第二个输入。
  • 选择所有语言,即将第二个输入设置为列名“targetLang”。

  • 因此,我没有将其与固定字符串“targetLang”进行比较。我想为该列选择所有可能的值(从translationChains中选择targetLang)。

    最佳答案

    查询参数只能代替文字值-也就是说,您通常会在其中放置带引号的字符串文字,带引号的日期文字或数字文字。因此,字符串值将始终被解释为字符串文字,就好像您已使用单引号将其放入查询中一样。

    对于列名,表名,SQL表达式,SQL关键字等,您必须在调用prepare()之前将这些值插值到SQL查询中。

    为了最安全,请使用白名单,这样用户输入就不会被逐字插入到SQL查询中。在查询中使用用户输入(或任何其他内容)之前,请始终对其进行验证。

    建立SQL查询时,我将written many examples列入白名单。

    您还可以在演示文稿SQL Injection Myths and Fallacies和我的书SQL Antipatterns: Avoiding the Pitfalls of Database Programming中看到示例。

    发表您的评论:

    我不确定您在做什么。听起来您要么想要t.targetLang等于一个文字数字,要么是一个固定的字符串'targetLang'。如果是这样,我根本不知道为什么要进行子查询-您应该仅使用查询参数作为值:

    where i.userID = ? And i.translated = 0
    and t.targetLang = ?
    
    Image.setString(2, langID); // either '3' or 'targetLang'
    

    但是我不确定我是否完全理解您的描述。该数字是否代表您要比较的列的位置?与t.targetLang在同一行吗?如果是这样,我仍然认为您不需要子查询。您可以使用类似以下的表达式:
    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.
    

    请参阅有关MySQL中FIELD()函数的手册,该手册在表达式列表中搜索第一个参数。它返回匹配字段的整数位置。

    使用此方法,您传递希望t.targetLang匹配的位置,这使您可以将动态零件作为值而不是列名进行传递。它还使您可以避免子查询。

    如果我仍然无法理解您的问题,请编辑原始问题并提供更多详细信息。 SHOW CREATE TABLE translationChains会有所帮助。您还可以回答一些我必须做的假设,例如您是否尝试将t.targetLang与同一行另一列中的值进行匹配?

    好吧,现在我对您的目标有了更好的了解。这是一个查询,可以满足您的需求:

    选择i.imageID,theImage,transitionRating
    从图像我
    INNER JOIN TranslationChains t
    开启t.imageId = i.imageid
    在哪里i.userID =? AND i.translated = 0
    和 ? IN(t.targetLang,'targetLang')

    您可以将第二个参数传递为与t.targetLang匹配的整数,或者传递与谓词中的'targetLang值匹配的文字字符串“targetLang”。

    但是,我不推荐这种解决方案,因为它可能无法很好地使用索引,因此它可能必须通过将string参数与integer列进行比较来执行类型转换。

    要匹配所有语言时,更好的做法是在WHERE子句中不带最后一项的情况下执行查询。也就是说,仅在您希望查询获取特定语言时,才在您的应用程序中有条件地附加该术语。否则,忽略该术语并跳过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()
    

    关于mysql - 在没有 ' '的情况下将字符串插入准备好的语句,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15818819/

    10-11 05:15