WHERE - IS NULL not working in SQLite? - sqlite

Here's a strange one:
I can filter on NOT NULLS from SQLite, but not NULLS:
This works:
SELECT * FROM project WHERE parent_id NOT NULL;
These don't:
SELECT * FROM project WHERE parent_id IS NULL;
SELECT * FROM project WHERE parent_id ISNULL;
SELECT * FROM project WHERE parent_id NULL;
All return:
There is a problem with the syntax of your query (Query was not
executed) ...
UPDATE:
I am doing this with PHP- through my code with ezSQl and using the PHPLiteAdmin interface
Using the PHPLiteAdmin demo, this expression works- so now I'm suspecting a version issue with my PHP's SQLite? Could that be? Wasn't this expression always valid?
UPDATE 2:
When I run the code from PHP using ezSQL, the PHP warning is:
PHP Warning: SQL logic error or missing database
Is there a way to get more information out of PHP? This is maddeningly opaque and weird, especially because the same statement in the CLI works fine...
UPDATE 3
The only other possible clue I have is that the databases that I create with PHP cannot be read by the CLI, and vice versa. I get:
Error: file is encrypted or is not a database
So there's definitly two SQlite flavors butting heads here. (See this) Still, why the invalid statment??
UPDATE 4
OK I think I've traced the problem to the culprit, if not the reason- The DB I created with PHP ezSQL is the one where the IS NULL statement fails. If I create the DB using PHP's SQLite3 class, the statement works fine, and moreover, I can access the DB from the CLI, whereas ezSQL created DB gave the file is encrypted error.
So I did a little digging into ezSQL code- Off the bat I see it uses PDO methods, not the newer SQLite3 class. Maybe that's something- I'm not gonna waste further time on it...
In any case, I've found my solution, which is to steer clear of ezSQL, and just use PHPs SQLite3 class.

a IS b and a IS NOT b is the general form where a and b are expressions.
This is generally only seen in a IS NULL and a IS NOT NULL cases. There are also ISNULL and NOTNULL (also NOT NULL) operators which are short-hands for the previous expressions, respectively (they only take in a single operand).
The SQL understood in SQLite expressions is covered in SQLite Query Language: Expressions.
Make sure that (previous) statements have been terminated with a ; first if using the CLI.
These are all valid to negate a "null match":
expr NOT NULL
expr NOTNULL
expr IS NOT NULL
These are all valid to "match null":
expr ISNULL
expr IS NULL
Since all of the above constructs are themselves expressions the negations are also valid (e.g. NOT (expr NOT NULL) is equivalent to expr IS NULL).
Happy coding.
The proof in the pudding:
SQLite version 3.7.7.1 2011-06-28 17:39:05
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> create table x (y int null);
sqlite> select * from x where y isnull;
sqlite> select * from x where y notnull;
sqlite> select * from x where y not null;
sqlite> select * from x where y is null;
sqlite> select * from x where y is not null;
sqlite>

The problem could stem from how SQLite handles empty columns. For instance just because a column is empty does not mean it is NULL. Have you tested against ""?
SELECT * FROM project WHERE parent_id = ""
That query might return results.

In Android SQLite, field IS NULL doesn't work either.
field = 'null' does. Give it a try in your environment

This works on SQLite in SQLite Manager for Firefox:
select * from foo where not baz is not null
The query above returns rows where column [baz] is null. :-) Yarin, maybe it will work for you?
(The 'not' before the column name is not a typo).
This query too finds rows where baz is null:
select * from foo where [baz] is null

If you are testing perhaps the PK column (?) and the column is being treated as synonym for rowid, then no rows will have a rowid that's null.

try where your_col_name ISNULL
wheres ISNULL contains no space

Related

Sqlite: conditionally query two tables, one will not exist

I am sure I can solve this programmatically, but I am curious if I can do this in one query.
Context:
I will be querying multiple databases, some will have a table; 'table', others will instead have the table; 'table_v2'. I want to run the same SELECT statement on the table that exists. I know I can check if a table exists, but I want to know if I can do it all in one statement.
psuedo code summary of what I want to do in one statement:
if 'SELECT name FROM sqlite_master WHERE type='table' AND name=''table'; is not empty:
SELECT * FROM table;
else
SELECT * FROM table_v2;
I am beholden to constraints out of my control.
Thoughts:
Could I have the table name be a regex?
Can I run both SELECTS, ignore the failed result, and just return the success?
Generally, you can't do either. The query planner in SQLite needs to know the name of the table beforehand, and it must be valid so it can determine which paths to take.
You can use the loadable extension eval to build up the SQL query based off of the schema. Though, this exposes a variant of the same issue, since the query planner needs the table name, you need to build up the entire SQL statement, then run it, so you'll need two eval calls.
SELECT EVAL(
'SELECT * FROM ''' ||
EVAL('SELECT name FROM sqlite_master WHERE type=''table'' AND name IN (''table'', ''table_v2'');') ||
''';'
);
To use the eval function, you'll need to either build and load the extension as a library, or build it into your own custom build of SQLite itself.
Of course, I can't answer if you should do this.

Why TableAdapter doesn't recognize #parameter

I am using table adapter Query configuration wizard in Visual studio 2013 for getting data from my database. For some queries like this:
SELECT *
FROM ItemsTable
ORDER BY date_of_creation desc, time_of_creation desc
OFFSET (#PageNumber - 1) * #RowsPerPage ROWS
FETCH NEXT #RowsPerPage ROWS ONLY
it doesn't recognize the #pageNumber as a paremeter and it cannot generate function that has these arguments while it works fine for queries like:
Select Top (#count) * from items_table
Why does in first query tableadapter fail to generate function with mentioned arguments whereas it can generate function fine for second one for example: tableadapter.getDataByCount(?int count)
Am I forced to use stored procedure, if yes since I don't know anything about it how?
Update: The Problem exactly occurs in TableAdapter Configuration Wizard in DataSet editor (VS 2013) and it doesn't generate functions with these parameters some times it says #RowsPerPage should be declared! but it should generate a function with this arguments I found that it happens when we don't use #parameter_name in clause other than SELECT and WHERE for example in this query we used the, in Offset clause.
I can't tell you how to fix it in ASP, but here is a simple stored procedure that should do the same thing:
CREATE PROCEDURE dbo.ReturnPageOfItems
(
#pageNumber INT,
#rowsPerPage INT
)
AS
BEGIN;
SELECT *
FROM dbo.ItemsTable
ORDER BY date_of_creation desc,
time_of_creation desc
OFFSET (#pageNumber - 1) * #rowsperpage ROWS
FETCH NEXT #rowsPerPage ROWS ONLY;
END;
This will also perform better than simply passing the query, because SQL Server will take advantage of the cached query plan created for the procedure on its first execution. It is best practice not to use SELECT *, as that can cause maintenance trouble for you if there are schema changes to the table(s) involved, so I encourage you to spell out the columns in which you're actually interested. The documentation for the CREATE PROCEDURE command is available here, and it spells out the many various options you have in greater detail. However, the code above should work fine as is.
If you need to grant access to your application user so they can use this proc, that code is
GRANT EXECUTE ON OBJECT::dbo.ReturnPageOfItems TO userName;

Unable to use QtSqlDriver to retrieve data from a table with "." in column names

I have a SQlite database I'm trying to read with the QtSql.QSqlTableModel. The issue is it won't read any table where the field name contains a "." via the setTable method.
As an example if I have table called MyTable with the column names
(ID, Name.First, Name.Last)
I can manually select it with the query
SELECT * FROM MyTable
or
SELECT "ID", "Name.First", "Name.Last" and all is ok
However, the QSqlTableModel won't use that query but will error out with "no such column Name.First Unable to execute statement."
When I dug a little deeper the SQLITE driver in Qt would rewrite the query as
SELECT "ID", "Name"."First", "Name"."Last" FROM MyTable
But this SELECT statement is wrong and would try and grab columns from another table "Name" but I want a column called "Name.First" in the table "MyTable"
I tried to circumvent this by subclassing the setTable method which worked for getting the data into the TableView:
def tableName(self):
return self._tableName
def setTable(self, tableName):
self.clear()
self._tableName = tableName
self.setQuery(QtSql.QSqlQuery("SELECT * FROM {0}".format(tableName), self.database()))
However, reimplementing the method in this fashion broke the method submitAll().
Inside the File Save method I have the following:
ok = self.tableModel.submitAll()
if not ok:
logging.error('Error %s' % self.tableModel.lastError().text())
logging.error('Error %s' % self.tableModel.query().lastQuery())
return False
This gives this log:
ERROR:root:Error near "SET": syntax error Unable to execute statement
ERROR:root:Error SELECT * FROM MyTable
But when I don't reimplement the setTable method, submitAll() works without errors.
So... How do I circumvent the "." in the Column name problem and also have the submitAll() work?
BTW: I agree that having "." in the field names for SQL tables is not a good idea but this is pairing up with another tool that generates the sqlite file in this manner which I have no control over.
http://www.qtcentre.org/archive/index.php/t-7565.html
http://www.qtforum.org/article/11245/sqlite-how-to-insert-text-that-contains-character-in-field.html
Looks like you just need to call one or both of the functions below before sending it to the database, in order to sanitize the input.
http://qt-project.org/doc/qt-4.8/qsqlquery.html#bindValue
http://qt-project.org/doc/qt-4.8/qsqlquery.html#prepare
http://xkcd.com/327/
:)
Hope that helps.

Lua sqlite Select statement

I have the following code to create a database table if it does not already exist then check if the current user is in the database or not. I do this by selecting the user with id equal to their device id. The code right now should print hello world and then go to forms. However when I run the code nothing happens, no errors and no print statement. Any ideas why this might be happening?
local tablesetup = [[CREATE TABLE IF NOT EXISTS User (id VARCHAR(255) PRIMARY KEY, name);]]
db:exec(tablesetup)
--Check if the user is in the database already
for row in db:nrows("SELECT * FROM User WHERE id = " .. "'" .. system.getInfo("deviceID") .. "'") do
print("hello")
if(row.id == nil) then
print("world")
storyboard.gotoScene("forms")
end
end
nrows returns all of the rows produced by a query. If no rows were produced in a query (because, for example, the item(s) you were looking for was not found), then the loop will not start. Because there was no row that matched the query.
If you're looking to detect if a query succeeded or not, then you'll need to actually check that.
Also, please stop building queries with string concatenation. Learn how to use prepared statements with proper value binding. It's much cleaner and has the benefit of not leaving you open to SQL injection attacks.

The full-text query parameter for Fulltext Query String is not valid

I am using Full Text Search with LINQ in my application and as this is not supported by LINQ I use a table-valued function workaround. The function is created on SQL Server 2008.
Surprisingly, I get error “The full-text query parameter for Fulltext Query String is not valid” when I search for a simply text e.g. “manager”
I used SQL Server Profiler and found out that LINQ generated the parameter as nvarchar(4000) instead of nvarchar(250) which is in my function.
The biggest surprise came when I changed my SQL Server function so it accepts parameter as nvarchar(4000) instead of nvarchar(250) and the problem is solved.
I was also playing to change the parameter to nvarchar(2000) and less but this also didn’t work.
Does anybody know why this behaves this way?
Updated on 18th November 2013 - Good news and bad news
Good news - I am now using Entity Framework 6 for this particular example and it is not anymore needed to use nvarchar(4000)
Bad news - You have to use instead nvarchar(max) :-(
For an expanation see the following link http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/1a46d676-32f0-44a4-b39f-61a17bccb8e3/.
In my case I had to force JAVA to call my Table-Value-Function with matching datatype as below
query.setParameter(0, variable, new **StringNVarcharType**() )
You need to ensure the size of the varchar (or nvarchar) variables are the same in your sql function and where they are declared.
In my case I had a function that declared the variable as nvarchar(100) but the stored procedure that called the function declared the variable passed in as nvarchar(200). Changing the function to be the same as the stored procedure variable fixed this.
Code below shows the non-working case with the inconsistently sized nvarchars.
CREATE FUNCTION [dbo].[udf_FullTextSearch](#searchExpression nvarchar(100))
RETURNS TABLE
AS
RETURN
SELECT *
FROM Company c
WHERE contains(c.Name, #searchExpression)
GO
DECLARE #searchExpression nvarchar(200) = '"ltd"'
SELECT * FROM [dbo].[udf_FullTextSearch](#searchExpression)

Resources