IHP - sorting on field in joined tables? - ihp

Is it possible to sort on a field in a joined table? For instance, if I want something like:
(modules, pagination) <- query #Module
|> innerJoin #User (#userId, #id)
|> orderByJoinedTable #email
|> paginate
Is this currently possible?

This is currently not possible. You would need to use a handwritten sql query for this using sqlQuery

Related

SqlQuery and SqlFieldsQuery

it looks that SqlQuery only supports sql that starts with select *? Doesn't it support other sql that only select some columns like
select id, name from person and maps the columns to the corresponding POJO?
If I use SqlFieldQuery to run sql, the result is a QueryCursor of List(each List contains one record of the result). But if the sql starts with select *, the this list's contents would be different with field query like:
select id,name,age from person
For the select *, each List is constructed with 3 parts:
the first elment is the key of the cache
the second element is the pojo object that contains the data
the tailing element are the values for each column.
Why was it so designed? If I don't know what the sql that SqlFieldsQuery runs , then I need additional effort to figure out what the List contains.
SqlQuery returns key and value objects, while SqlFieldsQuery allows to select specific fields. Which one to use depends on your use case.
Currently select * indeed includes predefined _key and _val fields, and this will be improved in the future. However, generally it's a good practice to list fields you want to fetch when running SQL queries (this is true for any SQL database, not only Ignite). This way your code will be protected from unexpected behavior in case schema is changed, for example.

Can I evade a where clause with a parameter instead of adding OR 1=1 to the query?

Now I have a long query and I'd like to alternate with such a statement
where userid=#userid
But I have other parameters which change flow, so, I want to have two options, selecting one user or any user
Can I send a username so that It can select and user? like we do in LIKE statements, we send
where username LIKE "%%"
and we get all records, how can I do that with INT?
Because my query is parameterized, I can't add "OR 1=1" like
where userid=1 or 1=1
should I use BETWEEN and get two parameters, so when I select one record, I'll enter userid-1 and userid+1 as two paramters, and get one user, and when I wand to select all, I'll enter 1 and 1 million.
Is it a logical way for parameterized queries or is there another way, with one parameter?
SOLUTION
Typically this is done using
WHERE userid = #userid OR #userid IS NULL
Another variation (if the userid column is not nullable):
WHERE userid = COALESCE(#userid, userid)
Yet another (for ints) is to say
WHERE userid BETWEEN COALESCE(#userid, 1)
AND COALESCE(#userid, 2000000000); -- well, 2147whatever
But if you have a lot of these conditions and every time the query is run the parameters change, you could be locking yourself into bad plans that aren't always appropriate. So sometimes the answer is to generate dynamic SQL:
SET #sql = #sql + CASE WHEN #userid IS NOT NULL THEN
N' AND userid = ' + CONVERT(VARCHAR(12), #userid);
Couple this with OPTION RECOMPILE and/or the instance setting "optimize for ad hoc workloads" you'll only stuff up the plan cache with plans for versions of the query that are executed more than once.
Would something along the following lines work?
SELECT * FROM Users WHERE UserID = #UserID OR #SelectAllUsers = 1
You set up #SelectAllUsers as an integer you can pass as 1 or any other number. If it's 1, it will select all users, otherwise you'll only select the passed in user.
where userId > -1
would that work?
Parameterized queries are there to keep sql injection from happening. Why don't you make a specific query with no parameters or WHERE clause like SELECT * FROM users?

MySQL implementation of an iterator

is it a way to implement an iterator in mysql which could return a column as
"1/10"
"2/10"
...
"10/10"
Lets say the form is a/b, as input we have only b. Is it possible to solve this without procedure?
EDIT
An example. We have a relation PRINTS (id, work_id, edition_no) and EDITIONS (id, work_id, size, edition_size). For web-interface I am trying to render a select with possible options for prints. Html-options should look like
<option value="1">1/10</option>
<option value="2">2/10</option>
All my select list I render with SQL from database, but in this case I do not see any possibility to get it from database in way I need it. Sql should return 2 columns with option-value and option-text. That is a question.
SQL is all about relations, that is, tables. The natural way would be to create a one-column table with 10 (or however much you want) consecutive numbers, index it by that column, and select enough numbers from there, using order by and limit.
Use the CONCAT function to concatenate strings in MySQL:
SELECT CONCAT('<option value="', p.edition_no, '">', p.edition_no. '/', e.edition_size, '</option>')
FROM PRINTS p
JOIN EDITIONS e ON e.work_id = p.work_id

How do you write the SQL for a PreparedStatement using a WHERE x IN clause?

I have a query that looks like this:
SELECT last_name,
first_name,
middle_initial
FROM names
WHERE last_name IN ('smith', 'jones', 'brown')
I need to be able to parameterize the list in the IN clause to write it as a JDBC PreparedStatement. This list could contain any number of names in it.
Is the correct way to do this:
SELECT last_name,
first_name,
middle_initial
FROM names
WHERE last_name IN (?)
and then build a list of parameters? Or is there a better (more correct) way to do that?
In short, you can't out of the box. However, with Spring you can do what you want. See How to generate a dynamic "in (...)" sql list through Spring JdbcTemplate?
Standard SQL doesn't allow the IN clause to be parameterized into a single variable -- only dynamic SQL, the SQL query being constructed as a string prior to execution with the comma separated list of values is supported.
I'm going to research this topic, as well. I've been guilty of writing similar code and never felt 100% comfortable with it. I suppose I'd like to find something on "variable SQL parameter lists".
In code, using hibernate, and given a String of comma-delimited order Ids, I've used:
Session s = getSession();
Criteria crit = s.createCriteria(this.getOrderListingClass());
crit.add(Expression.sql(String.format("{alias}.orderId in (%s)", orderIds)));
crit.add(Expression.eq("status", OrderInfo.Order_STATUS_UNFILLED));
orders = crit.list();
Whereas orderId is really part of a "SELECT x FROM y WHERE IN (%s)".
I did run the orderIds String through a validator prior to passing it to hibernate - being fearful of injections, etc.
Something else that I've been meaning to do is check the limit on SQL parameters and number of characters in the query. I seem to recall hitting a limit somewhere around 2000+ (with MS SQL). That's something to consider if you go with this approach.
I think this is kludgy... to be passing off that many Ids in a Where-clause, but it's a section of code that needs refactoring. Thankfully, the use case has only seen a handful of Ids queried at any one time.
You could also construct your query as a stored procedure that takes the parameterized list as a varchar. For example, in sql server:
CREATE PROCEDURE dbo.[procedure_name]
#IN_LIST VARCHAR(MAX)
AS
BEGIN
DECLARE #SQL VARCHAR(MAX)
SET #SQL = '
SELECT last_name,
first_name,
middle_initial
FROM names
WHERE last_name IN (' + #IN_LIST + ')'
EXECUTE(#SQL)
END
Just make sure your #IN_LIST is formatted as a string that includes the single quotes and commas. For example in java:
String inList = "'smith','jones','brown'";
If You use MS SQL Server, try reshape your TSQL to use UDF, Maybe this my post can help You

How to find all records that share the same field value as some other record?

I need to extract all records which have a field which does NOT have a unique value.
I can't figure out an elegant way to do it - using annotation or some other way. I see a "value_annotate" method to the object manager but it's unclear if it's at all related.
Currently I'm using the inelegant way of simple looping through all values and doing a get on the value, and if there's an exception it means it's not unique..
Thanks
I can't say much about the Django part, but the query would look something like:
SELECT *
FROM foo
WHERE id IN (
SELECT MAX(id)
FROM foo
GROUP BY bar
HAVING COUNT(*)=1)
This will return all records where the "bar" field is unique.
I'd go direct to a raw query in this case. This'll look something like the following, assuming you're using Django 1.2:
query = """
SELECT *
FROM table
GROUP BY field
HAVING COUNT(*) > 1
"""
non_uniques = Table.objects.raw(query)
For earlier than 1.2, see the django docs on raw queries