I'm trying to find a nice solution to a movie filtering system built in java and with a mysql database. The user is supposed to be able to filter which movies they wish to see based on a number of attributes, such as: director, actor, length, genre, year,...,. In total there are 11 fields which can be used to filter the query.
The problem is some of these fields can (and probably will) be left blank. For instance, maybe the user only wants to filter data based on a certain genre, director and length. Or maybe they only want to filter it based on the prodution studio, and dont care about the other filter options.
I have made a connection to the server, and the problem is in creating the "SQL_String" that I will use in statement.executeQuery(SQL_String).
Lets say I only wanted to filter for one field. Then I know I could write
String field = //user input (for example: actor)
String filter = //user input (for example: 'tom cruise')
String SQL_String = "SELECT * FROM Movies WHERE "+field + "=" +filter
But if i want to allow the user to filter based on several (or zero) fields, then I dont know how to write the code.
Some example queries could be:
"SELECT * FROM Movies WHERE (director = 'steven spielberg' AND genre = 'action' AND length >100)"
"SELECT * FROM Movies WHERE (type = 'tv-series' AND actor = 'bob odenkirk')"
So the user can specify which fields they want to filter (if any) and i need to come up with a java code that can take those into account and construct a query string.
Since you don't know how many fields the user will filter on but you do know that the data you're dealing with has two parts (the field and the filter), the first two things that come to my mind are maps and tuples. Since, unlike Python, Java does not have a built in tuple data type (to my knowledge), here is a small example solution that I thought of for your problem solved using Java's HashMap and Map classes.
In this example, I create a HashMap with the key being a string for the "field" and the value being a string for the "filter". You can set these values based on the user input wherever you have that in your code (in this example, simply hard-coded in the main method). Then you can loop through the key-value pairs in your HashMap (see this helpful post), appending the key and value as well as the additional characters necessary for the query. This is a simple example but shows a possible solution route.
If you want to make sure that this solution works for the cases where you filter value is an integer, then just add in another if-statement in the loop to try parsing for an integer and if one exists to not add the extra \' escape characters.
import java.util.HashMap;
import java.util.Map;
public class MovieQueryTest {
public static void main(String[] args) {
String SQL_Query = "SELECT * FROM Movies WHERE ";
HashMap<String, String> queryFilters = new HashMap<>();
queryFilters.put("director", "Steven Spielberg");
queryFilters.put("type", "tv-series");
queryFilters.put("actor", "Bob Odenkirk");
boolean firstQueryFilter = true;
for (Map.Entry<String, String> entry : queryFilters.entrySet()) {
if (firstQueryFilter) {
SQL_Query += entry.getKey() + "=\'" + entry.getValue() + "\'";
firstQueryFilter = false;
} else {
SQL_Query += " AND " + entry.getKey() + "=\'" + entry.getValue() + "\'";
}
}
System.out.println(SQL_Query);
}
}
Related
I've implemented a simple filtering method in Java by creating a composite String key (SaleType + SaleDate). Then I just put each sale by its unique key to a HashMap. As a result I have a HashMap with sales filtered by the SaleType + SaleDate key.
I've recently started learning Scala and want to try the same filtration logic with it. How may this be implemented using Scala opportunities? I suppose a filter method may be used. But how can I construct a String key from the Sale object and then put it to the uniqueSalesMap?
private static List<Sale> getUniqueSales(List<Sale> sales) {
Map<String, Sale> uniqueSalesMap = Maps.newHashMap();
for (Sale sale : sales) {
String saleKey = sale.getSaleType() + sale.getSaleDate();
uniqueSalesMap.put(saleKey, sale);
}
return new ArrayList<Sale>(uniqueSalesMap.values());
}
One way would using groupBy
sales.groupBy(s=>s.salesType +s.saleDate).values.map(_.head)
Here is a relatively concise way that avoids constructing any intermediate Maps:
import collection.breakOut
val m: Map[String, Sale] =
(for (s <- sales) yield (s.getSaleType + s.getSaleDate, s))(breakOut)
m.values.toList
but to be honest, I don't see much of an advantage when compared to the original Java code. You could have written
val m = collection.mutable.HashMap.empty[String, Sale]
for (s <- sales) {
m(s.getSaleType + s.getSaleDate) = s
}
m.values.toList
It doesn't seem any less clear to me.
This does what you want, but not in the way that you wanted to do it, so I'm not sure if it counts as an answer or not.
sales.map(s => s.saleType + s.saleDate).distinct
I want to create one report that you select product and storeName and returns all the sales per date (within a range).
The db view that helped me with other reports looks like this:
product - store_name - date
So far my approach is to return all records from the db in a list and then I do the following:
public void salesReport(String product, String store, String date){
List<RecordSalesInfo> salesResults = salesDao.getSales();
Map<String, Integer> mapper = new HashMap();
//calculation
for (RecordSalesInfo record : salesResults) {
StringBuilder key = new StringBuilder();
key.append(record.getProduct()).append(":")
.append(record.getStoreName()).append(":")
.append(record.getWageredDate()).append(":");
if (mapper.containsKey(key.toString())) {
Integer get = mapper.get(key.toString());
get++;
mapper.put(key.toString(), get);
} else {
mapper.put(key.toString(), 1);
}
}
for (String key : mapper.keySet()) {
if(key.toString.equals("Pen:London:13June2016"){
System.out.println("sales:" + mapper.get(key.toString);
}
}
}
the query in the salesDao(saving as "RecordSalesInfo") is:
SELECT
rs.product AS product,
rs.store_name AS store,
rs.date AS date,
rs.product_id AS productId
FROM sales rs
ORDER BY rs.product,rs.store_name,rs.date
The reason I didn't query "Count(blabla) where product='a' and store_name='b' and date='c' " is because the user changes the input using a jSlider very often (input=product,store,date), that means too many queries. So I thought it is better to take all the results from db and then display what the user needs.
A) Is there a better way to do this?
B) In the next phase the user will enter only the product and the store and I have to return the list of the sales by date, looking like this:
Pen - London (manual input)
12June2016 100
15June2016 30
19July2016 67
With what I have done so far, I can't get only the dates that I have sales, and I have to "search" from the hashMap for all dates(specific range). I think as a solution to change the key to "product:storeName" one the existing map and have as a value another map where the String will be the date and the Integer the amount of sales.
Again is there a better way on doing that?
What I would do is that I will not hold/keep a map, rather I will fetch the results as the query changes based on the JSlider etc.
You can do one thing that when a query is sent until its results are available you can disable your Jslider and show a spinner that notifies the user that processing is going on.
Once the result is available, enable the slider and hide the spinner.
To have all the data in the map does not seem a good idea. It will be a disconnected state of data.
My specific problem is related to an Android project but this is not a specific android question.
I am basically just trying to come up with a way I can query a database and return results not based on exact matches but based on similar terms even outside the scope of a search on whether a String "contains" the typed value.
So for example, lets say I have a entry called "Popeye's Catfish". And lets say somebody enters the term "P's CatSalmon" and are looking for that entry. I would like to return a query list that shows essentially a "most similar" match.
I admit I am a complete novice at database queries so there might be ready answers out there that I just can't find (I did look). There are a few ways I can think to do this:
I could break apart the search string and look for separate parts of each string in a "contains" search of the actual entry. For example I could break out "P" "Cat" and "Salmon" search all three and do some other code to find out what the best result is. However, I'm really not sure how I would code it so that the program could pick the best segments. How would it know to pick out "cat" for example without just iterating through every possibility (which is almost certainly not realistic)?
I could just let the users suffer for a while until tags exist. What I mean is, once the correct entry is found by the "proper" name, I could just let users tag it with associated names and then include that separate associated name in the search by later users.
I can't come up with anything better than that based on my current level of knowledge.
Thanks in advance for the help.
I'm guessing that this is some sort of find location app. So let's assume that the number of locations is small, say less than 200.
You would start by building a search that looks for the "words" that the user typed in the locations. In your example, we have "P's" and "CatSalmon". "CatSalmon won't match anything, and neither will "P's".
So you return something that looks like this:
Locations found for "P's CatSalmon"
-----------------------------------
No locations found. Try using different search terms.
So, our user types "P CatSalmon".
So you return all the locations that start with the letter P, then the locations that contain the letter P.
Something like this:
Locations found for "P CatSalmon"
---------------------------------
Popeye's Catfish
Public library
Hope Restaurant
...
Now, here's where it gets interesting.
When the user picks a location, you log the search term and the location selected.
In your example, the user would pick "Popeye's Catfish".
So later, you manually add this key value to a synonym map.
Key Value
--------- ----------
CatSalmon Catfish
Over time, your searches will get better because your users will define the synonyms.
So, to recap.
You search for locations that start with a word.
You search for locations that contain a word.
You look in the synonym map for synonyms, and you repeat the start / contain process with the synonym(s).
Start locations are displayed first, then contain locations.
Finally, you do all this work on the server with the database. You pass the sorted location list to the phone. Don't make the phone do all the work.
This is something I put together essentially highlighting the closest matched term with a query based on the number of sequential characters
public class SequenceMatches {
public static void main(String [] args)
{
HashMap<String, Integer> map = new HashMap<String, Integer>();
String query = "P's SalmonCat ";
map = addTermsToHashMap(map);// add terms to a hash map
map = compareFirstCharacter(map, query);// compare the initial first character
map= compareSequentialCharacters(map, query);// compare terms to query and add score based on the number of matches
printResults(map);
}
public static HashMap<String,Integer> addTermsToHashMap(HashMap<String,Integer> map){
String term = "Popeye's CatFish";
String otherTerm = "Popets CatSalmon";
map.put(term,0);
map.put(otherTerm,0);
return map;
}
public static HashMap<String,Integer> compareFirstCharacter(HashMap<String,Integer> map,String query){
for(Map.Entry<String,Integer> e: map.entrySet())
{
String term = e.getKey();
char [] termChar = term.toCharArray();
char [] queryChar = query.toCharArray();
if((queryChar[0]) == (termChar[0]))
{
int value = map.get(term);
map.put(term,++value);
}
}
return map;
}
public static HashMap<String,Integer> compareSequentialCharacters(HashMap<String,Integer> map,String query){
for(Map.Entry<String,Integer> e: map.entrySet())
{
String term = e.getKey();
char [] termChar = term.toCharArray();
char [] queryChar = query.toCharArray();
for(int i = 0; i < queryChar.length -1; i++)
{
for(int j = 0; j < termChar.length -1; j++)
{
if(queryChar[i] == termChar[j] )
{
if((queryChar[i + 1]) == (termChar[j + 1]))
{
System.out.println((queryChar[i + 1]) + " " + (termChar[j + 1]));
int value = map.get(term);
map.put(term,++value);
break;
}
}
}
}
}
return map;
}
public static void printResults(HashMap<String,Integer> map)
{
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey()+" : "+entry.getValue());
}
}
}
Hi I run a simple select query in oracle over a table and get a resultset. like select username, responsibility, project from mytable.
The resultset contains user details. there are multiple rows returned for each username with different values for responsibility and project.
Now I want to get a list of lists from this resultset which has one List per username and distinct values are concatenated in a comma seperated string.
So if Sam has multiple entries in the resultset then the output of my operation should give me:
UserList =
["Sam", "responsibility1,responsibility2,responsibility3...", "dept1,dept2,dept3.."],
[Some other User],
[and so on..]
Later I will write this to a csv file.
I cannot do this in the query itself for compatibility reasons, we have to support multiple databases, versions in future.
How do I do this in java or groovy?
Thanks
Java is quite easy.
You need a class to model each user.
You need a Map of username to User.
Each User contains a List of responsibility and a List of departments.
Then you iterate your resultset, find the User from the map on each row and add the responsibility and department to that User
Do you need the code or is that good enough?
HTH
Edit: Here's some Java starting code:
(Not checked for syntax or mistakes ;] )
public class User {
private final List<String> responsibility = new ArrayList<String>();
private final List<String> department = new ArrayList<String>();
...standard getters and setters
}
// Your code to do the read
public void executeRead() {
... obtain the resultset somehow here
Map<String, User> usernameToUser = new HashMap<String, User>():
while (rs.next) {
String username = rs.getString("username");
User user = usernameToUser.get(username);
if (user == null) {
user = new User(); // Create and remember a user the first time you see them
usernameToUser.put(username, user);
}
String responsiblity = rs.getString("responsiblity");
String department = rs.getString("department");
user.addResponsibility(responsibility);
user.addDepartment(department);
}
rs.close();
// Now you have the data structure of users in memory you can output
// it in whichever format you like e.g. HTML, CSV, etc
// Probably best to do this step in a totally separate place that can
// be switched out for a different output format in future.
}
I have a java Set of Result objects. My Result class definition looks like this:
private String url;
private String title;
private Set<String> keywords;
I have stored my information in a database table called Keywords which looks like this
Keywords = [id, url, title, keyword, date-time]
As you can see there isn't a one-to-one mapping between an object and a row in the database. I am using SQL (MySQL DB) to extract the values and have a suitable ResultSet object.
How do I check whether the Set already contains a Result with a given URL.
If the set already contains a Result object with the current URL I simply want to add the extra keyword to the Set of keywords, otherwise I create a new Result object for adding to the Set of Result objects.
When you iterate over the JDBC resultSet (to create your own set of Results) why don't you put them into a Map? To create the Map after the fact:
Map<String, List<Result>> map = new HashMap<String, List<Result>>();
for (Result r : resultSet) {
if (map.containsKey(r.url)) {
map.get(r.url).add(r);
} else {
List<Result> list = new ArrayList<Result>();
list.add(r);
map.put(r.url, list);
}
}
Then just use map.containsKey(url) to check.
Normalization is your friend
http://en.wikipedia.org/wiki/Database_normalization
If it's possible, I suggest changing your database design to eliminate this problem. Your current design requries storing the id, url, title and date-time once per key word, which could waste quite a bit of space if you have lots of key words
I would suggest having two tables. Assuming that the id field is guarenteed to be unique, the first table would store the id, url, title and date-time and would only have one row per id. The second table would store the id and a key word. You would insert multiple rows into this table as required.
Is that possible / does that make sense?
You can use a Map with the URLs as the keys:
Map<String, Result> map = new HashMap<String, Result>();
for (Result r : results) {
if (map.containsKey(r.url)) {
map.get(r.url).keywords.addAll(r.keywords);
} else {
map.put(r.url, r);
}
}
I think that you need to make an override on equals() method of your Result class. In that method you will put your logic that will check what you are looking for.
N.B. You also need to know that overrideng the equals() method, you need to override also hashCode() method.
For more on "overriding equals() and hashCode() methods" topic you can look at the this another question.