node to traverse cannot be null (Hibernate SQL) - sql

I'm performing a SQL query through hibernate, which looks like:
SELECT thi
FROM track_history_items thi
JOIN artists art
ON thi.artist_id = art.id
WHERE thi.type = "TrackBroadcast"
GROUP BY art.name
ORDER thi.createdAt DESC
but I'm getting the message that 'Node to traverse cannot be null!'. Anyone know what could be causing this?
--EDIT--
I'm pretty sure that this problem is being caused by the possibility of artist_id to be null. However, I can't prevent this, so can I just skip the rows track_history_item rows which have a null artist_id?

I have gotten that error only when using createQuery instead of createNamedQuery.
So when detecting this, hibernate throws the exception.
Query query = entityManager.createQuery("DS.findUser");

node to traverse cannot be null!
This is a generic Hibernate error message indicating a syntax problem in your query. As another example, forgetting to start a select clause with the word "SELECT" would yield the same error.
In this instance the syntax error is due to the on clause - HQL does not support them. Instead do a cross join like so:
FROM track_history_items thi, artists art
WHERE thi.type = "TrackBroadcast"
AND thi.artist_id = art.id
GROUP BY art.name
ORDER thi.createdAt DESC

I have come across this issue several times before as well and it has always been the case that the code was attempting to run a named query by calling createQuery instead of createNamedQuery, e.g. if you have a named query named "FIND_XXX" then the code would be calling entityManager.createQuery(FIND_XXX) which results in it trying to execute the String representing the name of the named query as if it was a standard dynamic query String (which is obviously a problem).

You can also get this error if you execute a query that has a syntax error, such as forgetting a comma in an update statement
update MyObject set field1=5 field2=4 WHERE id = 4
See how there is a missing comma between field1=5 and field2=4? You will get a node to traverse cannot be null error.

This error comes usually due to one of the most stupid reason that one would not have even imagined. If you dop copy-paste the query, some special characters get introduced and you start getting this error. Make sure you type the query manually and it will work fine. Atleast in my case it worked.

If you are using Hibernate 4 you should be calling:
Query query = session.getNamedQuery(Entity.NAMED_QUERY);
instead of
Query query = session.createQuery(Entity.NAMED_QUERY);
This happens because session.createQuery will try to create the query based on the string value of Entity.NAMED_QUERY for example:
String NAMED_QUERY = "Entity.namedQuery";
resulting in a incorrect HQL and raising a exception.

Related

Invalid Position in SQL WHERE Clause

I have a query I am writing that examines an ID field and derives an ID number from that column based on several criteria. Now that I have its logic written, I want to run the query on each criteria to see if the logic is working. So, the last part of my query for doing so is as follows:
FROM TABLE1
WHERE SOURCE_SYSTEM_NM = 'XYZ' AND ((STRLEFT(SOURCE_ARRANGEMENT_ID,4)) NOT IN ('23CC','21CC'))
LIMIT 10000
Essentially what I am trying to do here is tell it to return to me only items with SOURCE_SYSTEM_NM equal to 'XYZ', while eliminating any with a SOURCE_ARRANGEMENT_ID not having the first 4 characters equal to '21CC' or '23CC'. I have a third criteria I want to filter on as well, which is that the first three characters must be '0CC'.
My problem when I run this is I get back an "Invalid Position" error. I removed one of the strings from the criteria, and it works. So, I decided to add the second in its own 'NOT IN...' clause with an AND between them, but that resulted in the same error.
If I had to guess, the NOT IN ('21CC','23CC') puts an AND between them and I think that must be the root of my issue. The criteria in my CASE statement derives the ID number with the following:
WHEN (M_CRF_CU_PRODUCT_ARRANGEMENT.SOURCE_SYSTEM_NM) IN ('XYZ') AND STRLEFT(SOURCE_ARRANGEMENT_ID, 4) IN ('23CC','21CC') THEN STRRIGHT(SOURCE_ARRANGEMENT_ID, LENGTH(SOURCE_ARRANGEMENT_ID)-4)
WHEN (M_CRF_CU_PRODUCT_ARRANGEMENT.SOURCE_SYSTEM_NM) IN ('XYZ') AND STRLEFT(SOURCE_ARRANGEMENT_ID, 3) IN ('0CC') THEN STRRIGHT(SOURCE_ARRANGEMENT_ID, LENGTH(SOURCE_ARRANGEMENT_ID)-3)
WHEN (M_CRF_CU_PRODUCT_ARRANGEMENT.SOURCE_SYSTEM_NM) IN ('XYZ') AND (STRLEFT(SOURCE_ARRANGEMENT_ID, 4) NOT IN ('23CC','21CC') OR STRLEFT(SOURCE_ARRANGEMENT_ID, 3) NOT IN ('0CC')) THEN (SOURCE_ARRANGEMENT_ID)
So with that, I am just trying to check each criteria to make sure the ID derived/created is correct. I need to filter down to get results for that last WHEN statement above, but I keep getting that "Invalid Position" in my WHERE statement at the end. I am using Aginity to run this query and it's running against an IBM Netezza database. Thanks in advance!
I figured out what the issue was on this - when performing
STRRIGHT(SOURCE_ARRANGEMENT_ID, LENGTH(SOURCE_ARRANGEMENT_ID)-4)
There are some of those Arrangement IDs that do not have 4 characters, thus I was getting an "Invalid Position". I fixed this by updating this query to use substring() instead:
SUBSTRING(SOURCE_ARRANGEMENT_ID,5,LENGTH(SOURCE_ARRANGEMENT_ID))
This fixed my issue. Just wanted to post an answer in case others have this issue. It s not Netezza specific, this will react this way with any SQL variant.

LookupRecord in SQL statement with WHERE clause does not work

Background
I am creating a database to tracks lab samples. I wish to put a restriction in place that prevents a technician from reporting multiple results for the same sample.
Current strategy
My query called qselReport lists all samples being reported.
SELECT tblResult.strSampleName, tblResult.ysnReport FROM tblResult WHERE (((tblResult.ysnReport)=True));
When a technician wishes to report a result for a given sample, I use a Before Change Event to check for that sample in qselReport (the code block below is my event macro N.B. it is not VBA).
If Updated("ysnReport") And Old.[ysnReport]=False Then
Look Up A Record In qselReport
Where Condition = [strSampleName]=[tblResult].[strSampleName]
Alias
RaiseError
Error Number 1
Error Description This sample is already being reported.
End If
That all works fine and dandy. The error message pops up if a second result is selected to report for a sample.
The problem
I like to keep things as sleek as possible, so I don't want qselReport unless it's absolutely necessary. So I made a slight adjustment to the LookupRecord block so that it operates on a SQL statement rather than on the query. Here's what that looks like (again N.B. not VBA, just a macro):
If Updated("ysnReport") And Old.[ysnReport]=False Then
Look Up A Record In SELECT tblResult.strSampleName, tblResult.ysnReport FROM tblResult WHERE [tblResult].[ysnReport]=True;
Where Condition = [strSampleName]=[tblResult].[strSampleName]
Alias
RaiseError
Error Number 1
Error Description This sample is already being reported.
End If
Now I get the error message every time that a result is reported, even if it's the first instance for that sample. From what I can tell, the issue is that the SQL statement WHERE clause does not filter the records to only those where ysnReport=True.
Can anyone explain why I can do LookupRecord in a query but not LookupRecord in an identical SQL statement? Thanks for the input.
If you want things as sleek as possible, at least performance-wise, a stored query should, in principle, outperform dynamic SQL.
Syntax-wise, I'm not familiar with the macro constructs, but I'd consider enclosing the select statement in parentheses if it accepts them and also adding an explicit alias. I suspect that alias would in turn need to be referenced in your WHERE condition:
Where Condition = MySelect.[strSampleName]=[tblResult].[strSampleName]
Alias MySelect
I found the solution to my problem. The SQL statement where clause needed to be moved to the LookupRecord data block Where condition. This works:
If Updated("ysnReport") And Old.[ysnReport]=False Then
Look Up A Record In SELECT tblResult.strSampleName, tblResult.ysnReport FROM tblResult;
Where Condition = [ysnReport]=True And [strSampleName]=[tblResult].[strSampleName]
Alias
RaiseError
Error Number 1
Error Description This sample is already being reported.
End If

Rails doesn't respect my select fields using includes

I want write a query with active record and seems it never respect what I want to do. So, here are my example:
Phonogram.preload(:bpms).includes(:bpms).select("phonograms.id", "bpms.bpm")
This query returns all my fields from phonograms and bpms. The problem is that I need put more 15 relationships in this query.
I also tried use joins but didn't work properly. I've 10 phonograms and returns just 3.
Someone experienced that? How did you solve it properly?
Cheers.
select with includes does not produce consistent behavior. It appears that if the included association returns no results, select will work properly, if it returns results, the select statement will have no effect. In fact, it will be completely ignored, such that your select statement could reference invalid table names and no error would be produced. select with joins will produce consistent behavior.
That's why you better go with joins like:
Phonogram.joins(:bpms).select("phonograms.id", "bpms.bpm")

Why is my ActiveRecord order method denying knowledge of a derived column from a select method?

I have written an ActiveRecord query designed to order my invoices by the sum of a column in an associated table (Invoice has_many :item_numbers). It involves some complex (for me) class methods but it ends up like this;
Invoice.where(user_id: 1, deleted: false, status: 'Sent').joins(:item_numbers).select('invoices.*, sum(item_numbers.amount) as total').group('invoices.id').order('total asc').limit(20)
If I run this query in the console I get the expected result - my first twenty invoices ordered by the total of their item_numbers. When it runs in the development server though, I get the following error from Postgresql;
PG::Error: ERROR: column "total" does not exist
As the query that is run on the server depends on a lot of scopes and class methods, to check that the query is correct, I called .to_sql on it and the output in the browser was;
SELECT invoices.*, sum(item_numbers.amount_with_gst) as total FROM "invoices" INNER JOIN "item_numbers" ON "item_numbers"."invoice_id" = "invoices"."id" WHERE "invoices"."user_id" = 1 AND "invoices"."deleted" = 'f' AND "invoices"."status" = 'Sent' GROUP BY invoices.id ORDER BY total asc LIMIT 20
I get exactly the same output if I call .to_sql on the query itself in the console, and if I put this output into Invoice.find_by_sql in the console I don't get the error.
This feels like some sort of weird bug, but I know that the bug is most likely mine. I have hunted for a few hours now with no clues - can anyone see what I'm doing wrong?
This is not a problem with ActiveRecord. As you demonstrated, ActiveRecord has no problem with your code and it happily creates a SQL statement. But one which PostgreSQL doesn´t like: The PG::Error exception is a low level exception coming from the database adapter stating that your SQL query is not valid.
PostgreSQL simply doesn't support expression aliases in the ORDER BY statement. (Have a look at the documentation for ORDER BY)
You have to repeat the expression in the order statement:
Invoice.select('invoices.*, sum(item_numbers.amount) as total')
.order('sum(item_numbers.amount) asc')
Don't worry, the query optimizer will detect that and your sum is still calculated just once.
Most likely you are using a different DBMS on your console and your development server. (MySQL or SQLite?) Some database engines accept expression aliases, some don't.

LINQ to SQL query fails using two Contains statements

I have two tables, DH_MASTER and DH_ALIAS. DH_MASTER contains information about a person, including their name. DH_ALIAS contains AKA records about the person. The tables are linked by the Operator field which is a primary key in DH_MASTER.
The users want to search by the name stored in DH_MASTER as well as search through all of their known aliases. If any matches are found in either DH_MASTER or DH_ALIAS then the DH_MASTER entity should be returned.
I created the query below which should give the results I described (return any DH_MASTER rows where the DH_MASTER.Name == name or DH_MASTER.DH_ALIAs(n).Name == name).
It works fine if I use only ONE of the .Contains lines. It doesn't matter which one I use. But the execution fails when I try to use BOTH at the same time.
qry = From m In Context.DH_MASTERs _
Where (m.Name.Contains(name)) _
OrElse ((From a In m.DH_ALIAs _
Where a.Name.Contains(name)).Count() > 0) _
Select m
The LinqToSQL Query evaluates to the following SQL code (as displayed in the SQL Server Query Visualizer)
SELECT [t0].[Operator], [t0].[Name], [t0].[Version]
FROM [DHOWNER].[DH_MASTER] AS [t0]
WHERE ([t0].[Name] LIKE %smith%) OR (((
SELECT COUNT(*)
FROM [DHOWNER].[DH_ALIAS] AS [t1]
WHERE ([t1].[Name] LIKE %smith%) AND ([t1].[Operator] = [t0].[Operator])
)) > 0)
EDIT: Checking the "Show Original" box in the Query Visualizer reveals the parameterized query as expected so this block of text below should be ignored.
I don't know if this is a problem or not but the `.Contains` evaluates to a `LIKE` expression (which is what I expect to happen) but the parameter is not encapsulated in apostrophes.
The interesting thing is that if I copy/paste the SQL Query into SQL 2005 Query Analyzer and add the apostrophes around the LIKE parameters, it runs just fine. In fact, it's lightning quick (blink of an eye) even with more than 2 million rows.
But when the LINQ query runs, the web app locks up for about 31 seconds before it finally fails with this error on gv.DataBind: Exception has been thrown by the target of an invocation.
With this innerException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
Does anyone know why this happens and how the behavior can be worked around? It's driving me nuts because the LinqToSql-generated SQL runs fine in query analyzer!
Update:
I have refactored my code based on the techniques in the answer. This works!
qry = From m In qry _
Where m.Name.Contains(name) OrElse _
m.DH_ALIAs.Any(Function(aliasRec) aliasRec.Name.Contains(name)) _
Select m
This might not be appropriate, since your problem is different, but I remember a problem in one of my programs: Contains() would not work (in my case it would throw an Exception when evaluating), so maybe the Contains-method is a bit broken.
I replaced
result.Contains( x )
with
result.Any( p => p == x )
which did work.
Can you try if that works? At least it might be a step in the right direction.
Linq to sql doesn't specify values directly into the query, it uses parameters. Are you sure it had the contains parameter value directly in the sql?
Anyway, the timeout is likely caused by a deadlock: the query wants to read from a row in a table which is locked by another (insert/update) query /transaction and that query apparently takes longer to complete.