I'm trying to retrieve data out of a legacy database.
The column in the table is defined as a DECIMAL(13,0) containing account numbers.
The column data type cannot be changed as it will have a major impact on the legacy system. Essentially all programs using the table need to be changed and then recompiled which is not an option.
We have a requirement to find all records where the account number contains a value, for example the user could search for 12345 and all accounts with an account number containing 12345 should be returned.
If this was a CHAR/VARCHAR, I would use:
criteriaBuilder.like(root.<String>get(Record_.accountNumber), searchTerm)
As a result of the column defined as DECIMAL(13,0), the accountNumber property is a double.
Is there a way to perform a like on a DECIMAL/double field?
The SQL would be
SELECT * FROM ACCOUNTS WHERE accountNumber LIKE '%12345%'
I have not actually tried this, but I believe it should work
criteriaBuilder.like(
root.get(Record_.accountNumber).as(String.class),
searchTerm)
This should generate a query kind of like this:
SELECT * FROM ACCOUNTS WHERE CAST(accountNumber AS text) LIKE '%12345%'
Related
I'm using
jdbcTemplate to make JDBC connections to a mySQL DB
prepared statements to protect myself as much as possible from SQL injection attacks
in need to accept requests from the user to sort the data on any of a dozen different columns
the following statement
jdbcTemplate.query("SELECT * FROM TABLE1 ORDER BY ? ?", colName, sortOrder);
Of course this doesn't work, because the variable bindings aren't supposed to specify column names just parameter values for expressions in the query.
So...how are people solving this issue? Just doing the sort in Java code seems like an easy solution, but since I'm getting a variable string for the column to sort on, and a variable telling me the sort order....that's an ugly number of comparator-conditions to cover. This seems like it should be a common problem with a common pattern to solve it...
Placeholders ? can only be used for parameter values but not with column and sort order directions. So the standard way to do this as is pointed e.g. here is to use String#format() or something similar to append your column name and order value to your query.
Another option is to use Spring Data JPA where you can give to your method as an argument an instance of type Sort which can contain all needed info for database to sort.
I would just concatenate the column name and the order to the SQL query, but only after
verifying that the column name and order are valid in this context.
sanitizing them to counter any attempt of SQL Injection attack.
I feel this is efficient compared to fetching the results to the application layer and sorting them here.
My suggestion is the mapping of keys and columns. It's a safe solution.
At the beginning, we initiate our map in the simplest possible way. For convenience, I overloaded the get (Obiect key) method to return the default column ("fullName") in case of failure. This will protect against SqlExeption.
static Map<String,String> sortCol;
{
sortCol = new HashMap<String, String>(){
{//Enter all data for mapping
put("name","fullName");
put("rok","year");
put("rate","likes");
put("count-rate","countRate");
}
/**
*
* #param key for column name
* #return column name otherwise default "fullName"
*/
#Override
public String get(Object key) {
String col =super.get(key);
return null==col?"fullName":col;
}
};
}
Here is a simple example of use.
String sqlQuery= "Select \"fullName\",year,likes,count-rate, country ..."+
"from blaBla..."+
"where blaBla..."+
"order by "+sortCol.get("keySort") "\n"; // keySort can have the value name, count-rate etc ..
By the way, you should never reveal the real names of columns in user interfaces, such as REST or SOAP etc ... For the attacker, this is a great help.
I want to design Address book with following fields
UID Name PhoneNumber1 PhoneNumber2
UID is to identify the name uniquely. Lets say i want to save 2 million records.
Now i want to structure how to save this records, so that it can be searchable by both Name and phoneNumber.
Which data structure and search technique i should go with.
Thanks in advance
What if you have conflicting names?
John Smith could return multiple times.
It appears that you are better off just using PhoneNumber1/PhoneNumber2 as your search variables.
I'd recommend a HashTable to do this, as it allows O(1) for searching, and with 2 million records, you don't want it to take forever to find someone.
Normalise that to the following tables and columns:
Names: UID, Name
PhoneNumbers: UID, SN, PhoneNumber
SN serial number, so 1 or 2 (and in the future, 3 to 1000 as well)
Each search you do should run two queries, one for each table (or one UNION query on both tables)
SELECT UID, Name
FROM Names
WHERE Name = '%<search string>%'
SELECT UID, PhoneNumber
FROM PhoneNumbers
WHERE PhoneNumber = '%<search string>%'
ORDER BY UID # so that multiple matches with same user appear together
Combining the results of both queries can be done in Java.
Why don't you design a class AddressBook
class AddressBook{
private Integer uuid;
private String name;
private Integer phoneNumber1;
private Integer phoneNumber2;
//getters & setters
}
Create a AddressBook Table in your database with the corresponding fields. uuid will be the primary key. Persist the AddressBook object.
To search by name
select * from AddressBook where name ="something";
To search by phone number
select * from AddressBook where phoneNumber1="something";
That depends on what are your main targets :
If requirement dvelopment is done and you have decided to use a relational data model for data storage and retrieval then #aneroid answer is an option.
Have in mind that:
Using WHERE Name = '%<search string>%' will force a considerable cost on RDMS engine. You may seek advanced full text search techniques in large scale data, based on your RDBMS.
If performance is the main target, using relational in memory databases will be an option.
In case RDBMS can be skipped, then java lang data structures
will come in handy, see here they are forged in terms of time complexity.
I have to work with a POJO "Order" that 8 fields and each of these fields is a column in the "order" table. The DB schema is denormalized (and worse, deemed final and unchangeable) so now I have to write a search module that can execute a search with any combination of the above 8 fields.
Are there any approaches on how to do this? Right now I get the input in a new POJO and go through eight IF statements looking for values that are not NULL. Each time I find such a value I add it to the WHERE condition in my SELECT statement.
Is this the best I can hope for? Is it arguably better to select on some minimum of criteria and then iterate over the received collection in memory, only keeping the entries that match the remaining criteria? I can provide pseudo code if that would be useful. Working on Java 1.7, JSF 2.2 and MySQL.
Each time I find such a value I add it to the WHERE condition in my SELECT statement.
This is a prime target for Sql Injection attacks!
Would something like the following work with MySql?
SELECT *
FROM SomeTable
WHERE (#param1 IS NULL OR SomeTable.SomeColumn1 = #param1) OR
(#param2 IS NULL OR SomeTable.SomeColumn2 = #param2) OR
(#param3 IS NULL OR SomeTable.SomeColumn3 = #param3) OR
/* .... */
We need to update DB2 database with following type of data with store procedure from java application.
ManId ManaFirstName ManLastName CubicleId Unit EmpId EmpFirstName EmpLastName
2345 Steeven Rodrigue 12345RT HR 2456 John Graham
45464 Peter Black
Here, the columns related Emp (Emp Id , Emp First Name and Emp Last Name) is actually array, it can any number of employees from my front application for one manager.
We need to pass these values in Store Procedure and process in SP. However, I am not able to find any array type datatype in db2.
I know I can take following two approaches :-
1. Delimited value :- Have varchar column and append all the values with help of delimiter and split in SP.
2456,John,Graham|45464,Peter,Black
2. Have separate SP and call in batch.
However, I am looking for approach where I can pass them in single go and some more structured datatype. Does DB2 have datatype like array to support this or any way to create custom datatype.
I am using Spring JDBCTemplate at front end to call SP (I am flexible to change that) and DB2 as database.\
P.S. :- Open queries is not option for me , need to call SP only.
This SP is going to be called from java directly, so if have to use custom datatype, only scope is to define it in store procedure which is being called
Since the data types of Emp Id , Emp First Name and Emp Last Name are probably different, you should use a DB2 ROW type to contain them, not ARRAY. In Java that would be represented by java.sql.Struct. You can also pass an ARRAY of ROW types to the stored procedure. Check the manual for details and examples.
Background : I have a database table called Contact. All users of my system have details of their contacts in this table including a firstname, a lastname, and also a varchar field called 'UniqueId'. Users of the system may put anything in the UniqueId field, as long as it is unique from that user's other contact's unique ids.
Aim : I now need to change my code so a unique id is automatically generated if the user does not provide one. This should be short and visually pleasing. Ideally it could just be an auto-incrementing number. However, AUTO_INCREMENT works for an integer field, not a varchar field.
Also note that each contact UniqueId needs to be unique from the other contacts of that user, but not neccesarily unique to the entire system. Therefore, the following UniqueIds are valid :
Contact
UserId Firstname Lastname UniqueId
1 Bob Jones 1
1 Harold Smith 2
2 Joe Bloggs 1
Question : So, how can I achieve this? Is there a reliable and clean way to get the database to generate a unique id for each contact in the existing UniqueId varchar field (Which is my preference if possible)? Or am I forced to make Java go and get the next available unique id, and if so, what is the most reliable way of doing this? Or any alternative solution?
Edit - 11th April AM: We use hibernate to map our fields. I'm just beginning to research if that may provide an alternative solution? Any opinions?
Edit - 11th April PM: 2 options are currently standing out, but neither seem as ideal as I would like.
1. As #eis suggests, I could have an auto-incrementing field in addition to my current varchar field. Then, either when a contact is saved the int can also be saved in the varchar field, or when a contact is retrieved the int can be used if the varchar is empty. But it feels messy and wrong to use two fields rather than one
2. I am looking into using a hibernate generator, as discussed here. But this involves holding a count elsewhere of the next id, and Java code, and seems to massively overcomplicate the process.
If my existing uniqueId field had been an int field, AUTO_INCREMENT would simply work, and work nicely. Is there no way to make the database generate this but save it as a String?
I think what you really should do is ditch your current 'uniqueid' and generate new ones that are really unique across the system, being always autogenerated and never provided by the user. You would need to do separate work to migrate to the new system. That's the only way I see to keep it sane. User could provide something like an alias to be more visually pleasing, if needs be.
On the upside, you could use autoincrement then.
Ok, one additional option, if you really really want what you're asking. You could have a prefix like §§§§ that is never allowed for a user, and always autogenerate ids based on that, like §§§§1, §§§§2 etc. If you disallow anything starting with that prefix from the end user, you would know that there would be no collisions, and you could just generate them one-by-one whenever needed.
Sequences would be ideal to generate numbers to it. You don't have sequences in MySQL, but you could emulate them for example like this.
I apologize, I really don't know MySQL syntax, but here's how I'd do it in SQL Server. Hopefully that will still have some value to you. Basically, I'm just counting the number of existing contacts and returning it as a varchar.
CREATE FUNCTION GetNewUniqueId
(#UserId int)
RETURNS varchar(3)
AS
BEGIN
DECLARE #Count int;
SELECT #Count = COUNT(*)
FROM Contacts
WHERE UserId = #UserId;
SET #Count = #Count + 1;
RETURN CAST(#Count AS varchar(3));
END
But if you really want something "visually pleasing," why not try returning something more like Firstname + Lastname?
CREATE FUNCTION GetNewUniqueId
(#UserId int, #FirstName varchar(255), #LastName varchar(255))
RETURNS varchar(515)
AS
BEGIN
DECLARE #UniqueId varchar(515), #Count int;
SET #UniqueId = #FirstName + #LastName;
SELECT #Count = COUNT(*)
FROM Contacts
WHERE UserId = #UserId AND LEFT(UniqueId, LEN(#UniqueId)) = #UniqueId;
IF #Count > 0
SET #UniqueId = #UniqueId + '_' + CAST(#Count + 1 AS varchar(3));
RETURN #UniqueId;
END