8

そのため、4 つのメニュー選択 (product、location、courseType、および category) があり、すべて null にすることができます (JSF を使用してプログラムされていますが、SQL の質問であるため、この質問には関係ありません)。

メニューを選択すると、マネージド Bean にユーザーが選択した変数が送信され、準備済みステートメントを使用して、ユーザーが選択したメニューからの情報 (存在する場合) を使用してデータベース テーブルが検索されます。

ユーザーがメニュー項目を null のままにすると、すべてを検索する必要があります。

ユーザーがメニュー項目の 1 つ、2 つ、または 3 つを情報とともに残し、他の 1 つを null のままにした場合、それに応じて検索する必要があります。

私の問題は、Bean 内の一連の if/then ステートメントを、すべての適切な sql ステートメントに関連付けずにどのように行うかです。

または、これをすべて行うことができるより良いSQLステートメントが1つありますか?

Java で準備済みステートメントを使用しています。

私はこれを試しました:

if (product != null && location != null && courseType != null && category != null) {
            pstmt = conn.prepareStatement("select * FROM Courses WHERE "
                    + "product = ? "
                    + "and location = ? "
                    + "and courseType = ? "
                    + "and category = ?");

            pstmt.setString(1, product);
            pstmt.setString(2, location);
            pstmt.setString(3, courseType);
            pstmt.setString(4, category);
        } else if (product == null && location != null && courseType != null && category != null) {
            pstmt = conn.prepareStatement("select * FROM Courses WHERE "
                    + "location = ? "
                    + "and courseType = ? "
                    + "and category = ?");


            pstmt.setString(1, location);
            pstmt.setString(2, courseType);
            pstmt.setString(3, category);
        } 

などなどですが、1がnullで他がそうではない場合ごとに、これを16回行う必要がありますか? よりスマートな方法が必要です (SQL ステートメントを 1 つ使用するか、Java の if/then ステートメントをいくつか使用するかのいずれか)。

ルイージ・メンドーサのおかげで更新!私のコードは次のように機能します:

pstmt = conn.prepareStatement("select * FROM Courses WHERE " 
         + "(product = ? or ? is null) " 
         + "and (location = ? or ? is null) " 
         + "and (courseType = ? or ? is null)" 
         + "and (category = ? or ? is null)"); 

         pstmt.setString(1, product);
         pstmt.setString(2, product);
         pstmt.setString(3, location);
         pstmt.setString(4, location);
         pstmt.setString(5, courseType);
         pstmt.setString(6, courseType);
         pstmt.setString(7, category);
         pstmt.setString(8, category);


        rset = pstmt.executeQuery();

更新ええ、別のmysqlデータベース(おそらく別のバージョンなど)では、 is null の代わりに = "" を使用する必要がありました

4

2 に答える 2

7

選択した値のデフォルト値があると仮定しますNULL(を使用してそれを行う別の方法がわからないためPreparedStatement'0'(例として)。

これを知って、私はこの種の SQL を使用する傾向があります。

SELECT *
FROM Courses
WHERE
    (product = ? or ? = '0')
    and (location = ?  or ? = '0')
    and (courseType = ? or ? = '0')
    and (category = ? or ? = '0')

このアプローチでは、使用法を活用しIF、データベースに作業を処理させます。これの唯一の悪い点は、すべての変数を 2 回設定する必要があることです (この人生では何も無料ではありません =\ )。


編集:あなたの要件に基づいてテストを行いました。最初に SQL テーブルとコンテンツ:

create table pruebaMultiSelect
(id int primary key auto_increment,
nombre varchar(50),
tipo varchar(10),
categoria varchar(10));

insert into pruebaMultiSelect values
(null, 'Luiggi', 'A', 'X');

insert into pruebaMultiSelect values
(null, 'Thomas', 'A', 'Y');

insert into pruebaMultiSelect values
(null, 'Jose', 'B', 'X');

insert into pruebaMultiSelect values
(null, 'Trina', 'B', 'Y');

次に、関連する Java コード:

public class DBTest {

    public void testPreparedStatement(String p1, String p2) throws SQLException {
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            con = getConnection();
            pstmt = con.prepareStatement("SELECT * FROM pruebaMultiSelect WHERE (tipo = ? OR ? = 'EMPTY') "
                    + "AND (categoria = ? OR ? = 'EMPTY')");
            pstmt.setString(1, p1);
            pstmt.setString(2, p1);
            pstmt.setString(3, p2);
            pstmt.setString(4, p2);
            rs = pstmt.executeQuery();
            while (rs.next()) {
                System.out.printf("%5d %15s\n", rs.getInt(1), rs.getString(2));
            }
        } catch(ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            rs.close();
            pstmt.close();
            con.close();
        }
    }

    public Connection getConnection() throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.jdbc.Driver");
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/luiggi_test", "user", "password");
    }

    public static void main(String[] args) throws SQLException {
        //this will return all the data
        String p1 = "EMPTY";
        String p2 = "EMPTY";
        new DBTest().testPreparedStatement(p1, p2);
    }
}

MySQL 5.1.18 を使用してテスト済み。

于 2013-02-27T20:44:29.297 に答える
1

私は、次のようなヘルパー メソッドを使用して動的クエリを作成する傾向があります。

StringBuilder query = new StringBuidler();
query.append("SELECT foo, bar FROM baz");
query.append(buildProductClause(product));
query.append(buildLocationClause(location));
query.append(buildCourseTypeClause(courseType));
// etc...

準備済みステートメントを引き続き使用する場合は、メンバー フィールドを使用して引数の配列を作成できます。

于 2013-02-27T20:41:30.610 に答える