store procedure nulls or zero value in column - stored-procedures

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

Related

Create dynamic SQL based on column names passed through a string

I need to find out rows that are present in table A and missing from table B (using LEFT JOIN) wherein table A and table B are two tables with same structure but within different schema.
But the query has to be constructed using Dynamic SQL and the columns that need to be used for performing JOIN are stored in a string. How to extract the column names from string and use them to dynamically construct below query :
Database is Azure SQL Server
eg :
DECLARE #ColNames NVARCHAR(150) = 'col1,col2'
Query to be constructed based on columns defined in ColNames :-
SELECT *
FROM Table A
Left Join
Table B
ON A.col1 = B.col1
AND A.col2 = B.col2
AND B.col1 IS NULL AND B.col2 IS NULL
If the number of columns in #ColNames is more then the SELECT statement needs to cater for all the column.
Without knowing the full context, try this:
DECLARE #ColNames NVARCHAR(150) = 'col1,col2'
DECLARE #JoinContion NVARCHAR(MAX) = ''
DECLARE #WhereCondition NVARCHAR(MAX) = ''
SELECT #JoinContion += CONCAT('[a].', QUOTENAME(Value), ' = ', '[b].', QUOTENAME(Value), (CASE WHEN LEAD(Value) OVER(ORDER BY Value) IS NOT NULL THEN ' AND ' ELSE '' END))
,#WhereCondition += CONCAT('[a].', QUOTENAME(Value), ' IS NULL', (CASE WHEN LEAD(Value) OVER(ORDER BY Value) IS NOT NULL THEN ' AND ' ELSE '' END))
FROM STRING_SPLIT(#ColNames,N',')
SELECT #JoinContion, #WhereCondition
String_Split: To split the input string into columns
Lead: to determine if we need the AND keyword when it's not the last row.
Be aware the NOT EXISTS is probably a better solution then LEFT JOIN

join / union in presto to keep email in one column

I'm trying to join two tables together in presto,
select o.email
, o.user_id
, c.email
, c.sessions
from datasource o
full join datasource2 c
on o.email = c.email
this yields:
email user_id email sessions
jeff#sessions.com 123 NULL NULL
mike#berkley.com 987 NULL NULL
jared#swiss.com 384 jared#swiss.com 14
steph#berk.com 333 NULL NULL
NULL NULL lisa#hart.com 12
the problem with this is that I want to do multiple joins on multiple data sources using email, the only workaround I can think of is to use this as a subquery, and create a new column that takes one, and if null, takes the other, then perform the full join on datasource3, rinse repeat.
You want to use COALESCE which will chose the not null of the two values.
COALESCE is very useful for a lot of things. It can take more than two values and will return the first non NULL value it gets. If all of them are NULL it will simply return NULL.
SELECT
COALLESCE(o.email, c.email) AS email
, o.user_id
, c.sessions
FROM datasource o
FULL JOIN datasource2 c
ON o.email = c.email
For the official documentation on COALESCE see here:
https://prestodb.io/docs/current/functions/conditional.html

Get random word from table A that is not on table B?

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

LINQ to entity, wrong join type

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 )

Why do NULL fields get called equal?

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 )

Resources