I'm writing triggers to detect changes in fields in a database, and it appears I have to do really obnoxious things like
(SELECT SalesPrice FROM __old) <> (SELECT SalesPrice FROM __new)
or ((SELECT SalesPrice FROM __old) IS NULL and (SELECT SalesPrice FROM __new) IS NOT NULL)
or ((SELECT SalesPrice FROM __old) IS NOT NULL and (SELECT SalesPrice FROM __new) IS NULL)
rather than just
(SELECT SalesPrice FROM __old) <> (SELECT SalesPrice FROM __new)
to accurately detect if a field changed.
Am I missing something, or does Advantage effectively claim that NULL == any value? Is there a good reason for this behavior? Is this some weird thing in the SQL definition? Is there a more succinct way this that doesn't do 3 checks in place of one?
This is unfortunately how SQL works with NULL values. NULL is not equal to anything, it is UNKNOWN. For example,
somevalue == NULL -> unknown
somevalue <> NULL -> unknown
As a result it will never pass a "true" check
Null Values - Wikipedia
There are a couple of options:
A) Do not allow null values (I recommend combining this with a default value)
B) Use IFNULL to set the field to some value such as
(SELECT IFNULL(SalesPrice, -9999) FROM __OLD) <> (SELECT IFNULL(SalesPrice, -9999) FROM __NEW)
But I don't know if I necessarily like this since a value must be picked that would not be valid.
In SQL, NULL does not compare to anything, except the IS [NOT] NULL expression. If I understand you question correctly, the problem here is that NULL must equal to NULL. If that is the case, the check may be simplified to:
( SELECT CASE WHEN n.SalesPrice IS NULL and o.SalePrice IS NULL THEN TRUE
ELSE n.SalesPrice = o.SalesPrice END
FROM __old o, __new n )
Related
I have a cypher query as follows:
MATCH (u:User {uid:"984172414"})-[ru:EB]->
(c:Co)<-[rf:EB]-(f:User)-[rc :EB]->(cc:Co)
WHERE (cc.uid in ["84161623"]) AND (rc.from IS NOT NULL AND rc.to IS NULL) AND
((
ru.from IS NOT NULL AND
ru.to IS NOT NULL AND
(
(rf.from <= ru.to) OR
(ru.from <= rf.to)
)
) OR (
ru.from IS NOT NULL AND
ru.to IS NULL AND
(
(ru.from <= rf.to) OR
(rf.from IS NOT NULL AND rf.to IS NULL)
)
) OR (
ru.from IS NULL AND
ru.to IS NOT NULL AND
(
(rf.from <= ru.to) OR
(rf.from IS NULL AND rf.to IS NOT NULL)
)
))
RETURN cc.name as coname,
f.name as fname,
cc.uid as cuid,
f.uid as fuid,
labels(f) as flabels,
null as version
LIMIT 20
This takes about 16192 ms to resolve. I have an index on co.uid but seems like it's not working. If I remove the check cc.uid in ["84161623"] and run the following query:
MATCH (u:User {uid:"984172414"})-[ru:EB]->
(c:Co)<-[rf:EB]-(f:User)-[rc :EB]->(cc:Co)
WHERE (rc.from IS NOT NULL AND rc.to IS NULL) AND
((
ru.from IS NOT NULL AND
ru.to IS NOT NULL AND
(
(rf.from <= ru.to) OR
(ru.from <= rf.to)
)
) OR (
ru.from IS NOT NULL AND
ru.to IS NULL AND
(
(ru.from <= rf.to) OR
(rf.from IS NOT NULL AND rf.to IS NULL)
)
) OR (
ru.from IS NULL AND
ru.to IS NOT NULL AND
(
(rf.from <= ru.to) OR
(rf.from IS NULL AND rf.to IS NOT NULL)
)
))
RETURN cc.name as coname,
f.name as fname,
cc.uid as cuid,
f.uid as fuid,
labels(f) as flabels,
null as version
LIMIT 20
The query resolves in only 347 ms. I can't figure out what is wrong with the (cc.uid in ["84161623"]) statement and why does adding this to the query takes 16 seconds to resolve when I already have an index on the uid. Any help will be appreciated.
update
As suggested by #cybersam I tried making the use of USING INDEX but that results in the following error:
Cannot use index hint in this context. Index hints require using an equality comparison or IN condition in WHERE (either directly or as part of a top-level AND). The comparison cannot be between two property values. Note that the label and property comparison must be specified on a non-optional node
Try using a USING INDEX clause to provide a hint to use that index. The Cypher processing code does not always automatically generate the most efficient code.
For example, put this between the MATCH and WHERE clauses:
USING INDEX cc:Co(uuid)
You may also need to use additional USING INDEX clauses if there are other indices. Note, however, that neo4j can not use indices in all situations; and, even if it is possible, the resulting query could theoretically be slower due to other resulting changes to the query. So, take a look at the resulting profile and test the result to make sure you are happy with it.
Sounds like you may need to do some sanity checking.
First of all, is :Co.uid an int or a string? It looks like you're addressing it as if it's a string, yet the values themselves look numeric. If it's an int, you can get rid of the quotes.
Same with :User.uid.
If you've been comparing ints to strings all this time, try fixing that first to see if it solves the problem. If not, you'll want to start profiling and figuring out if/when the query isn't using your index.
Next, try simplifying and profiling the query to see if the indices are actually being used:
PROFILE MATCH (u:User {uid:"984172414"}), (cc:Co)
WHERE (cc.uid in ["84161623"])
RETURN u, cc
If they're both using NodeIndexSeek or NodeUniqueIndexSeek, and if the db hits seem reasonable, you might expand out to your entire path and continue profiling. However, it's worth checking for a performance improvement if you match on the start and end nodes first, like above, then try to do your additional pattern matching. For example:
PROFILE MATCH (u:User {uid:"984172414"}), (cc:Co)
WHERE (cc.uid in ["84161623"])
WITH u, cc
MATCH (u)-[ru:EB]->(c:Co)<-[rf:EB]-(f:User)-[rc :EB]->(cc)
WHERE (rc.from IS NOT NULL AND...
i have a store procedure,its meant for updating a table,when i execute it,it brings out nulls or zero values for a some columns.this is the logic used
IF OBJECT_ID('tempdb..#exxPresessions_john') IS NOT NULL
DROP TABLE #exxPresessions_john
SELECT c.claim_id,
c.completed_date,
wp.createdon,
COUNT(DISTINCT wp.WebSessionId) AS websessions
INTO #exxPresessions_john
FROM dbo.web_PageviewsID wp WITH (NOLOCK)
JOIN #CliamID_john c WITH (NOLOCK)
ON c.claim_id = wp.claimid
WHERE ClaimType IS NOT NULL
AND c.completed_date > wp.createdon
GROUP BY
claim_id,
completed_date,
createdon
ORDER BY claim_id;
CREATE INDEX idx_index2 ON #WebPresessions_nosa (claim_id);
this is the Condition
completed_date > created_date
.it returns NULL as completed_date is NULL or Zero
i tried this but it did not work
and ISNULL (c.completed_date,0)> wp.createdon
You need to add one more condition like this:
WHERE ClaimType IS NOT NULL
AND c.completed_date is not null --Removes the null completed_date
AND c.completed_date > wp.createdon
I have 2 tables as follow (that was a phpMyAdmin dump which is why it have the ALTER TABLE):
CREATE TABLE IF NOT EXISTS `definition` (
`id` int(10) unsigned NOT NULL,
`page_id` int(10) unsigned NOT NULL,
`title` varchar(255) COLLATE utf8_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=2621401 ;
CREATE TABLE IF NOT EXISTS `definition_used` (
`id` int(10) unsigned NOT NULL,
`word` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`ts_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=65 ;
ALTER TABLE `definition`
ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `page_id` (`page_id`), ADD KEY `title` (`title`);
ALTER TABLE `definition_used`
ADD PRIMARY KEY (`id`), ADD KEY `word` (`word`,`ts_created`);
ALTER TABLE `definition`
MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=2621401;
ALTER TABLE `definition_used`
MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=65;
A SQLFiddle can be found here...
And I need to get a unique random word from it, since I have millions of records on the definition table, using RAND directly, is not an option.
I do have a query that will get a random word, which is this one:
SELECT r1.title
FROM definition AS r1
JOIN (SELECT (RAND() * (SELECT MAX(id)
FROM definition
)
) AS id
) AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
However, that will pick words based on the id, without doing any of the checks I need to. Now let's say it picked a random id of 2 million and there was no usable words past it given r1.id >= r2.id so I get no result, but if it was less it could have had a lot of results.
Right now I have came down to this:
SELECT a.title
FROM definition a
LEFT JOIN definition_used b
ON a.title = b.word
WHERE (b.id IS NULL OR (b.ts_created = CURDATE())) AND
LOWER(a.title) LIKE #message
LIMIT 1
From the table definition_used I need to be sure that a word was not used today, in order to be reused, so a word can have multiple entries as long as the ts_created does not collide with the same date hence why I check for:
(b.id IS NULL OR (b.ts_created = CURDATE()))
However the words that come out have 0 randomization, how can I get a random word out of the list?
I've seen some other questions where you can do that with a single table using the max id to define a random entry but I have not reference from definition table to the definition_used table other than the word itself.
To put it simple, I need to be able to pick a random word from the available non-used words which is what I don't know how to go about.
Still looking for a better query/answer but, this is what I came down to which works, however takes about 2 seconds to get a word which I think can be further optimized so if anyone feel like giving it a shot and optimizing or posting a better query for this I will gladly accept it as the right answer.
SELECT r1.title
FROM definition AS r1
JOIN (SELECT (RAND() * (SELECT MAX(a.id)
FROM definition a
LEFT JOIN definition_used b
ON a.title = b.word
WHERE (b.id IS NULL OR
(b.ts_created = CURDATE())
) AND
LOWER(a.title) LIKE #word
)
) AS id
) AS r2
WHERE r1.id >= r2.id
ORDER BY r1.id ASC
LIMIT 1
This is the EXPLAIN of it in case anyone wanted to see:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 1
1 PRIMARY r1 range PRIMARY PRIMARY 4 NULL 1293640 Using where
2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
3 SUBQUERY a index NULL title 767 NULL 2587281 Using where; Using index
3 SUBQUERY b ref word word 767 sebot.a.title 1 Using where; Using index
I have a query that looks like so....
var q = Dal.TBLINVENTORies.Where(i => i.SHOWIT);
q = q.Where(i => i.dtStart < DateTime.Now || i.dtStart == null);
q = q.Where(i => i.dtEnd > DateTime.Now || i.dtEnd == null);
q = q.Where(i => i.sSystem.Contains("OE"));
q = q.Where(i => i.WS_ActiveList_ID == 0 || i.tblWS_ActiveList.WS_MasterList_ID == 16);
var test2 = q.ToList();
Immediately before the "ToList()", if I examine the query, I get the following sql (more or less)
SELECT [Extent1].*
FROM [dbo].[TBLINVENTORY] AS [Extent1]
INNER JOIN [dbo].[tblWS_ActiveList] AS [Extent2] ON [Extent1].[WS_ActiveList_ID] = [Extent2].[ID]
WHERE ([Extent1].[SHOWIT] = 1)
AND (([Extent1].[dtStart] < CAST( SysDateTime() AS datetime2)) OR ([Extent1].[dtStart] IS NULL))
AND (([Extent1].[dtEnd] > CAST( SysDateTime() AS datetime2)) OR ([Extent1].[dtEnd] IS NULL))
AND ([Extent1].[sSystem] LIKE '%OE%')
AND ([Extent1].[WS_ActiveList_ID] = 0 OR [Extent2].[WS_MasterList_ID] = 16)
Unfortunately, this is not what I need, because relationship between "Inventory" and "ActiveList" is not really 1-to-Many, but Zero-to-Many (I'm not sure I'm using the correct terms). Basically, An inventory item might or might not have a related "ActiveList".
If I change that raw SQL to use a LEFT OUTER JOIN, instead of an INNER JOIN, the SQL returns the values I expect.
What is needed to force the LEFT OUTER JOIN?
I've tried the recommended solution from Linq to entities - One to many relationship - need left outer join instead of cross join , but,
var q2 = from inv in Dal.TBLINVENTORies from al in inv.tblWS_ActiveList
returns an error:
Error 65 An expression of type 'xxxx.DAL.tblWS_ActiveList' is not allowed in a subsequent from clause in a query expression with source type 'System.Data.Entity.DbSet<xxxx.DAL.TBLINVENTORY>'. Type inference failed in the call to 'SelectMany'.
I wonder if my link/relationship is constructed incorrectly? Any other ideas?
Thanks!
EDIT :: Additional Data
-- create foreign key, but don't enforce on existing values
ALTER TABLE [dbo].[tblInventory] --the ONE Table
WITH NOCHECK
ADD CONSTRAINT [FK__tblInventory.WS_ActiveList_ID__tblWS_ActiveList.ID]
FOREIGN KEY([WS_ActiveList_ID])
REFERENCES [dbo].[tblWS_ActiveList] ([ID]) --the MANY Table
NOT FOR REPLICATION
GO
-- disable enforcement of the foreign key, but leave it in place (virtual key)
ALTER TABLE [dbo].[tblInventory]
NOCHECK CONSTRAINT [FK__tblInventory.WS_ActiveList_ID__tblWS_ActiveList.ID]
GO
and the definition of WS_ActiveList_ID:
[WS_ActiveList_ID] [int] NOT NULL CONSTRAINT [DF_TBLINVENTORY_WS_ActiveList_ID] DEFAULT (0),
Your main problem is that you've turned off the referential integrity checks in your database.
Apart from the obvious problem of bad data, this won't work with EF.
By far the best option is to make WS_ActiveList_ID nullable, update your data to change all the 0s to NULLs and turn the constraint back on.
If you can't do that, I think you'll have to generate a SQL statement as a string and execute it with dbContext.Database.SqlQuery<T> ( MSDN )
In Informix:
how to check for not null,
I have a field with datetime data type, and I don't have any default values for this field, but I have lot of empty/null records for this field.
I want a query that will render the records:
( cond like ) where my_curr_date_time != ""
but if I try this query, it is not working. Please tell which query for finding not null records.
... WHERE my_curr_date_time IS NOT NULL
NULL is a special value. It may mean "no value" or "value unknown". In SQL if you want to check if value is or not is NULL then you must use ... yes ... value IS NULL or value IS NOT NULL. It may be used with other conditions like:
... WHERE my_curr_date_time IS NOT NULL AND my_curr_date_time > start_dt