Question

I'm retrieving user input such as "tea, coffee, latte" from a JTextField, the following input is then queried to a particular result that includes the strings "tea, coffee, latte" within the database:

public void actionPerformed(ActionEvent e) {
    try {
        String abc = field.getText();
        StringTokenizer str = new StringTokenizer(abc);
        while (str.hasMoreTokens()) {
            str.nextToken((", ")).trim();
        }
        Class.forName("com.mysql.jdbc.Driver");
        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/intelli_db", "root", "root");
        PreparedStatement st1 = con.prepareStatement("SELECT * FROM SHOP WHERE DRINKS LIKE '%" + abc + "%' OR '%" + abc + "%' OR '%" + abc + "%' OR '%" + abc + "%'");
        ResultSet rs = st1.executeQuery();
        if (rs.next()) {
            String s = rs.getString(1);
            String s1 = rs.getString(2);
            String s2 = rs.getString(3);
            //Sets Records in TextFields.

            field6.setText(s2);

        } else {
            JOptionPane.showMessageDialog(null, "No such input found");
        }
        //Create Exception Handler
    } catch (Exception ex) {
        System.out.println(ex);
    }
}

however, I wish it to find the result of any combination of these strings, so "coffee, latte, tea" would also give the same result as ""tea, coffee, latte" would.

The database structure:

Menu_ID  
--------
1
Drinks
-------
tea, coffee, latte      
Hot_Drinks_Description
------------------------
There are various hot drinks available, including Earl Grey tea, white or black coffee or a Latte. 

Thus if the user types in either, tea or coffee or latte or a combination - separated by comma's, the result would display the description of the hot drinks available.

Was it helpful?

Solution

It seems that the problem is a little messy. This seems to be the situation:

You have a List of user inputs. You have have a database field that is, itself, as comma separated list.

You need to see if there is a permutation in the database that matches one of the permutations of your input.

First your query. From this answer this is how to create a prepared statement with an IN clause.

PreparedStatement st1 = con.prepareStatement("SELECT * FROM SHOP WHERE DRINKS IN (?)");
Array array = con.createArrayOf("VARCHAR", stringPermutations);
st1.setArray(1, array);

This essentially queries your database where DRINKS is one of IN.

Now onto creating the stringPermutations. This needs to be an Object[] of the comma separated permutations - to match the database.

First, get a Set<String> of the user inputs: something like this ought to do:

public Set<String> getInputs(final JTextComponent component) {
    final Set<String> inputs = new LinkedHashSet<>();
    for (final String input : component.getText().split("\\s+")) {
        inputs.add(input);
    }
    return inputs;
}

In Java 8:

public Set<String> getInputs(final JTextComponent component) {
    return Stream.of(component.getText().split("\\s+")).
            collect(Collectors.toSet());
}

Now you need to permute the inputs to get all possible combinations. You will have n! of them - this is many:

public List<Set<String>> permutations(final Set<String> input) {
    if (input.size() == 1) {
        return Arrays.asList(input);
    }
    final List<Set<String>> output = new ArrayList<>();
    final Iterator<String> iter = input.iterator();
    while (iter.hasNext()) {
        final String item = iter.next();
        final Set<String> copy = new LinkedHashSet<>(input);
        copy.remove(item);
        for (final Set<String> rest : permutations(copy)) {
            rest.add(item);
            output.add(rest);
        }
    }
    return output;
}

This is a recursive algorithm, it's pretty standard. The output is something like this:

[D, C, B, A]
[C, D, B, A]
[D, B, C, A]
[B, D, C, A]
[C, B, D, A]
[B, C, D, A]
[D, C, A, B]
[C, D, A, B]
[D, A, C, B]
[A, D, C, B]
[C, A, D, B]
[A, C, D, B]
[D, B, A, C]
[B, D, A, C]
[D, A, B, C]
[A, D, B, C]
[B, A, D, C]
[A, B, D, C]
[C, B, A, D]
[B, C, A, D]
[C, A, B, D]
[A, C, B, D]
[B, A, C, D]
[A, B, C, D]

So, for 4 input you get 4! = 24 permutations. Now we need to join those individual items into comma separated lists:

public List<String> combine(final List<Set<String>> toJoin) {
    final List<String> outputs = new ArrayList<>(toJoin.size());
    for (final Set<String> items : toJoin) {
        outputs.add(join(items));
    }
    return outputs;
}

private String join(final Set<String> items) {
    final Iterator<String> iter = items.iterator();
    final StringBuilder sb = new StringBuilder();
    sb.append(iter.next());
    while (iter.hasNext()) {
        sb.append(", ").append(iter.next());
    }
    return sb.toString();
}

Again, tidier in Java 8:

public List<String> combine(final List<Set<String>> toJoin) {
    return toJoin.stream().
            map(items -> items.stream().collect(Collectors.joining(", "))).
            collect(Collectors.toList());
}

Finally we can get the Object[] input to the PeparedStatement:

final Object[] stringPermutations = combine(permutations(getInputs(field))).toArray();
PreparedStatement st1 = con.prepareStatement("SELECT * FROM SHOP WHERE DRINKS IN (?)");
Array array = con.createArrayOf("VARCHAR", stringPermutations);
st1.setArray(1, array);

It should further be noted that you should be closing your resources, you can use the try-with-resources construct:

final Object[] stringPermutations = combine(permutations(getInputs(field))).toArray();
try (final Connection con = getConnection()) {
    try (final PreparedStatement st1 = con.prepareStatement("SELECT * FROM SHOP WHERE DRINKS IN (?)")) {
        Array array = con.createArrayOf("VARCHAR", stringPermutations);
        st1.setArray(1, array);
        try (final ResultSet rs = st1.executeQuery()) {
            //do stufd
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top