I have created two tables, lets call them table a and table b.
Table A consists of one column of strings called domainType
Table B consists of one column of strings which are substrings to table A's column (called topLevelDomain)
CREATE TABLE a ( rank int, name text, domainType text )
CREATE TABLE b ( topLevelDomain text, domainDescription text)
table a:
rank name domainType
1 a com
2 b co jp
3 c co cn
table b:
topLevelDomain domainDescription
com country1
in country2
cn country3
...
jp country30
I want to list the most popular descriptions(countries) according to the rank of the domainType
to show this:
Desired result:
country1 -------> since rank is 1 (in table a)
country30 ------> since rank is 2 (in table a)
country2 --------> since rank is 3 (in table a)
I'm having trouble 'relating' the topLevelDomain column with the domainType column and returning the descriptions with the top rank corresponding to the domainType. I hope this makes sense! please let me know to add anymore information.
You can join the tables with the use of the operator LIKE:
select b.domaindescription
from b left join a
on concat(' ', a.domaintype, ' ') like concat('% ', b.topleveldomain, ' %')
order by case when a.domaintype is null then 1 else 0 end, a.rank
See the demo.
Results:
| domaindescription |
| ----------------- |
| country1 |
| country30 |
| country3 |
| country2 |
Related
I want to do a data search on spring data jpa, with only one parameter but can search several items. I have list data, like this.
{
"id": 105,
"roomId": 43,
"floor": "1",
"roomNumber": "001",
"description": "Normal",
"status": "Vacant Clean"
},
{
"id": 11,
"bedTypeName": "King size"
},
{
"id": 39,
"categoryName": "President Suite"
}
I want to search by roomNumber,bedTypeName, and categoryName. But, in one parameter. For example i have #Param("roomNumber") for search 3 item. Example "roomNumber":"001"then show filter by rooomNumber. Example "roomNumber":"king size" then show filter by bedType. Example "roomNumber":"president suite" then show filter by categoryName. In one parameter can search many item.
Here is my repository
#Query("select a,b.bedType,b.roomCategory from RoomDetail a left outer join RoomMaster b on a.roomId = b.id where lower(a.roomNumber) interests like %:roomNumber% OR interests LIKE %:bedTypeName% OR interests LIKE %:categoryName%")
Page<RoomDetail> findByRoomNumberBedTypeRoomCategor(
#Param("roomNumber") String roomNumber, Pageable paging);
Have you tried using custom query methods via JpaRepository interface. With custom query methods you can generate your repos like :
public interface RoomDetailRepository extends PagingAndSortingRepository<RoomDetail, Integer> {
Page<RoomDetail> findByRoomNumberOrBedTypeOrRoomCategoryContains(String search, Pageable pageable);}
You can include sorting keywords in your method names as well.
You can use Specification instead of writing a painful query and vague JpaRepository method.
JpaSpecificationExecutor
At first extend JpaSpecificationExecutor in your repository interface,
interface RoomRepository extends JpaRepository<RoomDetail, Long>, JpaSpecificationExecutor<RoomDetail> {
// your other queries
}
Specification
You need to create Specification to lookup the value on needed columns,
public static Specification<RoomDetail> search(String value) {
String search = "%" + value + "%";
return (root, query, builder) -> builder.or(
builder.like(root.get("roomNumber"), search),
builder.like(root.get("bedTypeName"), search),
builder.like(root.get("categoryName"), search)
);
}
Search :)
Now you can use it where you want to search from.
Page<RoomDetail> filteredRooms = roomDetailRepository.findAll(search(value), paging);
FYI
As it looks at every value on roomNumber, bedTypeName, categoryName columns, there might be some cases on which multiple rooms will be filtered if the same value exists in different rooms columns unless you have unique values.
| id | roomid | floor | roomNumber | bedTypeName | categoryName | description | status |
|-----|--------|-------|------------|-------------|-----------------|------------------|--------------|
| 105 | 43 | 1 | 001 | Single | Junior Suite | Normal Size | Vacant Clean |
| 106 | 16 | 1 | 002 | Double | Business Suite | Couple Suitable | Booked |
| 121 | 23 | 2 | 020 | King Size | President Suite | Very comfortable | Vacant Clean |
In the above case if you give Size as a filter value you will get two rooms because id with 105 has Normal Size value on categoryName column and id with 121 has King Size on your bedTypeName column.
Moreover: to match the exact value, you may need to update search specification using builder.equals instead of builder.like but make sure that % should not be appended before and after the value.
Explore
Spring official documentation
spring-data-criteria-queries
spring-data-jpa-specification
The answer like this.. i have found the answer myself. And it works :)
#Query("select a,b.bedType,b.roomCategory from RoomDetail a left outer join RoomMaster b on a.roomId = b.id where lower(a.roomNumber) like %:filter% "
+ "or lower(b.bedType.bedTypeName) like %:filter% "
+ "or lower(b.roomCategory.categoryName) like %:filter%")
Page<RoomDetail> findByBedTypeOrRoomCategoryOrRoomNumber(#Param("filter") String Filter, Pageable paging);
I have:
TAG | REVIEW
A | hello
B | yay
A | win
in an ArrayList and I am trying to get:
TAG | COUNT
A | 8 //hello+win =8
B | 3 //yay =3
where count is the total number of characters in all strings with the same tag. I have been reading about Collections and Maps, but I am completely lost. Can someone explain how to solve this in pieces?
1) To get the count:
List<String,Integer> poll_reviewText_count=new ArrayList<>();
for(String l:poll_reviewText){
poll_reviewText_count.add({l[0],l[1].length()}) //TAG, COUNT
}
2) Then I think I need to combine all the instances of TAG that match into one sum. Not sure how to do this.
There isn't such thing as List<V, T> in java. Also you can't use a Map for your data, because inserting this :
TAG | REVIEW
A | hello
B | yay
A | win
In map, A | hello will get replaced by A | win (they have the same key).
A solution will be to create a class that will contain TAG and REVIEW information:
class Bar {
String tag;
String review;
// setters - getters
}
And then using the java stream, you can collect the data how you want:
Map<String, Integer> collect = poll_reviewText_count.stream()
.collect(Collectors.groupingBy(Bar::getTag, Collectors.summingInt(o -> o.getReview().length())));
I'm using Mockrunner to create a mock result set for a select statement. I have a loop that executes the select statement (which returns a single value). I want to have the result set return a different value each time, but I have been unable to find anything about how to specify the result set return value based on the times the statement has been called. Here's a pseudocode snippet of the code:
In the test Code:
String selectSQL = "someselectStmt";
StatementResultSetHandler stmtHandler = conn.GetStatementResultSetHandler();
MockResultSet result = stmtHandler.createResultSet();
result.addRow(new Integer[]{new Integer(1)});
stmtHandler.prepareResultSet(selectSQL, result);
In the Actual Target Class:
Integer[] Results = getResults(selectSQL);
while(Results.length != 0){
//do some stuff that change what gets returned in the select stmt
Results = getResults(selectSQL)
}
So essentially I'd like to return something like 1 on the first time through, 2 on the 2nd and nothing on the 3rd. I haven't found anything so far that I'd be able to leverage that could achieve this. The mocked select statement will always return whatever the last result set was to be associated with it (for instance if I created two MockResultSets and associated both with the same select stmt). Is this idea possible?
Looping Control Flow Working Within Java and SQL
If you're coding this one in Java, a way to make your code execution calls return different, sequenced results can be accomplished throughh a looping control flow statement such as a do-while-loop. This Wikipedia reference has a good discussion using the contrast of the do-while-loop between implementations in Java and also in different programming lanugages.
Some Additional Influences through Observation:
A clue from your work with the Mockrunner tool:
The mocked select statement will always return whatever the last result set was to be associated with it (for instance if I created two MockResultSets and associated both with the same select stmt)
This is the case because the SELECT statement must actually change as well or else repeating the query will also repeat the result output. A clue is that your SQL exists as a literal string value throughout the execution of the code. Strings can be altered through code and simple string manipulations.
String selectSQL = "someselectStmt";
StatementResultSetHandler stmtHandler = conn.GetStatementResultSetHandler();
MockResultSet result = stmtHandler.createResultSet();
result.addRow(new Integer[]{new Integer(1)});
stmtHandler.prepareResultSet(selectSQL, result);
in addition to the selectSQL variable, also add a line for a numeric variable to keep track of how many times the SQL statement is executed:
Int queryLoopCount = 0;
In the following target class:
Integer[] Results = getResults(selectSQL);
while(Results.length != 0){
//do some stuff that change what gets returned in the select stmt
Results = getResults(selectSQL)
}
Try rewriting this WHILE loop control following this example. In your pseudocode, you will keep pulling the same data from the call to getResults(selectSQL); because the query remains the same through every pass made through the code.
Setting up the Test Schema and Example SQL Statement
Here is a little workup using a single MySQL table that contains "testdata" output to be fed into some result set. The ID column could be a way of uniquely identifying each different record or "test case"
SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE testCaseData
(
id int primary key,
testdata_col1 int,
testdata_col2 varchar(20),
details varchar(30)
);
INSERT INTO testCaseData
(id, testdata_col1, testdata_col2, details)
VALUES
(1, 2021, 'alkaline gab', 'First Test'),
(2, 322, 'rebuked girdle', '2nd Test'),
(3, 123, 'municipal shunning', '3rd Test'),
(4, 4040, 'regal limerick', 'Skip Test'),
(5, 5550, 'admonished hundredth', '5th Test'),
(6, 98, 'docile pushover', '6th Test'),
(7, 21, 'mousiest festivity', 'Last Test');
commit;
Query 1 A Look at All the Test Data:
SELECT id, testdata_col1, testdata_col2, details
FROM testCaseData
Results:
| ID | TESTDATA_COL1 | TESTDATA_COL2 | DETAILS |
|----|---------------|----------------------|------------|
| 1 | 2021 | alkaline gab | First Test |
| 2 | 322 | rebuked girdle | 2nd Test |
| 3 | 123 | municipal shunning | 3rd Test |
| 4 | 4040 | regal limerick | Skip Test |
| 5 | 5550 | admonished hundredth | 5th Test |
| 6 | 98 | docile pushover | 6th Test |
| 7 | 21 | mousiest festivity | Last Test |
Query 2 Querying Only the First Record in the Table:
SELECT id, testdata_col1, testdata_col2, details
FROM testCaseData
WHERE id = 1
Results:
| ID | TESTDATA_COL1 | TESTDATA_COL2 | DETAILS |
|----|---------------|---------------|------------|
| 1 | 2021 | alkaline gab | First Test |
Query 3 Querying a Specific Test Record Within the Table:
SELECT id, testdata_col1, testdata_col2, details
FROM testCaseData
WHERE id = 2
Results:
| ID | TESTDATA_COL1 | TESTDATA_COL2 | DETAILS |
|----|---------------|----------------|----------|
| 2 | 322 | rebuked girdle | 2nd Test |
Query 4 Returning and Limiting the Output Set Size:
SELECT id, testdata_col1, testdata_col2, details
FROM testCaseData
WHERE id < 5
Results:
| ID | TESTDATA_COL1 | TESTDATA_COL2 | DETAILS |
|----|---------------|--------------------|------------|
| 1 | 2021 | alkaline gab | First Test |
| 2 | 322 | rebuked girdle | 2nd Test |
| 3 | 123 | municipal shunning | 3rd Test |
| 4 | 4040 | regal limerick | Skip Test |
Writing a Parameterized SQL Statement
I do not know if this difference in syntax yields the exact same results as your pseudocode, but I am recommending it from references of code structures that I know already work.
set condition value before loop
do{
// do some work
// update condition value
}while(condition);
The WHILE condition is instead at the end of the statement and should be based on a change to a value made within the looping block. We will now introduce the second variable, an int which tracks the number of times that the loop is iterated over:
String selectSQL = "someselectStmt";
String[] Results; = getResults(selectSQL);
// set condition value before loop
queryLoopCount = 0
do{
// do some work
Results = getResults(selectSQL);
// update condition value
queryLoopCount = queryLoopcount + 1;
}while(queryLoopCount < 6);
Where selectSQL comes from:
SELECT id, testdata_col1, testdata_col2, details
FROM testCaseData
WHERE id = 2;
And adapts with a built in parameter to:
selectSQL = 'SELECT id, testdata_col1, testdata_col2, details
FROM testCaseData
WHERE id = ' + queryLoopCount;
Mixing the string and integer values may not be a problem as in this reference on concatenated(+) values suggests: Anything concatenated to a string is converted to string (eg, "weight = " + kilograms).
Ideas for Specialized Case Requirements
You could introduce your own numbering sequence to get the records of each case to cycle through the reference table. There are a lot of possibilities by introducing an ORDER BY statement and altering the key ORDER BY value.
The "Skip" case. Within the Do-While loop, add a IF-THEN statement to conditionally skip a specific record.
set condition value before loop
do{
if ( queryLoopCount <> 4 ) {
// do some work}
// update condition value
queryLoopCount = queryLoopCount + 1;
}while(condition);
Using an if-then loop, this code sample will process all test records but will skip over the record of ID = 4 and continue through until the while loop condition is met.
I'm retrieving data from a table in a database and add the whole row to a TreeMap.
I'm using the following code:
ArrayList<String> listaValores = new ArrayList();
TreeMap<Integer, ArrayList> tmValores = new TreeMap<>();
(...)
while (rs.next())
{
listaValores.clear();
for(int i=2; i<=ncolunas; i++)
{
listaValores.add(rs.getString(i));
}
tmValores.put(rs.getInt(1), listaValores);
}
My TreeMap keys are inserted fine but the values are always repeated as the values from the last line as a result from the SELECT * FROM Table query.
So if my table is:
id | name | last name |
1 | joe | lewis |
2 | mark | spencer |
3 | mike | carter |
4 | duke | melvin |
My TreeMap contains:
1=> duke, melvin
2=> duke, melvin
3=> duke, melvin
4=> duke, melvin
Instead of (as I wanted)
1=> joe, lewis
2=> mark, spencer
3=> mike, carter
4=> duke melvin
Can anyone point me out where is the problem?
I believe you have to reassign the value of listaValores.
Simply change
listaValores.clear();
to
listaValores = new ArrayList<String>();
Objects in Java are passed around as references, so you are in fact adding the same list for all the keys in your map.
Since you clear it at every step and then add some values to it, it will contain just the last row, after the while loop has finished.
What you really want to do is to create an instance of ArrayList for every row and add that to your map, instead of clearing the values in the old one:
while (rs.next())
{
listaValores = new ArrayList<String>();
for(int i = 2; i <= ncolunas; i++)
{
listaValores.add(rs.getString(i));
}
tmValores.put(rs.getInt(1), listaValores);
}
I already have a database with every user's scores and other stats. But the scores aren't organized in any way that make it usable to make a leaderboard rank.
If the table looks something like this:
+----------+-------+-----+
| Username | Score | ... |
+----------+-------+-----+
| UserA | 900 | ... |
+----------+-------+-----+
| UserB | 200 | ... |
+----------+-------+-----+
| UserC | 850 | ... |
+----------+-------+-----+
| UserD | 450 | ... |
+----------+-------+-----+
There is no relation to position in the database and score. Now, what I want to do is create a query of the database collecting the scores for each user, then rearranging them by score. I figure this would be something like ORDER BY score DESC.
After ordering them in the correct way, I want to input the new values into a table with only username and rank, which I can query ingame to tell the rank of any given player requested.
ex:
+----------+------+
| Username | Rank |
+----------+------+
| UserA | 1 |
+----------+------+
| UserC | 2 |
+----------+------+
| UserD | 3 |
+----------+------+
| UserB | 4 |
+----------+------+
Now if I quered rank where username=UserA I would get 1
So what is my question? How do I, in java, query the database for score & username then rearrange the values into a new table based on the numerical rank, not score.
For specific user, this might work:
select username, score, (select count(h.username)+1 from users u, (select username, score from users) h where u.username = 'UserG' and (h.score > u.score)) as 'rating' from users where username = 'UserG';
Problem with setting a variable #rank like Alain suggested would be in case of duplicate scores, what if 2 users have a score of 100? Query above will rate them both as #5, if that is what you need.
The "In Java" is the only confusing part of your question. You want something like:
CREATE TABLE leaderboard (username varchar(50), score int unsigned, rank int unsigned)
INSERT INTO leaderboard (username, score, rank) SELECT username, score, #rank:=#rank+1 FROM scores_table, (SELECT #rank:=0) as run_once order by rank desc;
Untested, but that would be the concept. When it comes time to recalculate the leaderboard just:
DELETE * from leaderboard;
INSERT INTO leaderboard (username, score, rank) SELECT username, score, #rank:=#rank+1 FROM scores_table, (SELECT #rank:=0) as run_once order by score desc;
Make the database, um, return the data you need in the format you want:
set #rank = 0;
select username, #rank := #rank + 1 as rank
from user_scores
order by score desc
No Java magic required.
There was a similar discussion in this thread.
In general it's better to just select ordering by score and then put the query result into an array list. 0th item would be the person with the best score, 1st item person with second score, etc.
If you really need to select with ranking in the result set try using one of the examples in the linked discussion.