Inconsistent Result - Update versus Select - sql

I'm running the below statement and can't understand why the update affects 0 rows while a select with the same join and where return 1 row. They are both of type Varchar and crmnumberAC is bigger so should be able to take the string from AccountNumber. Thoughts?
begin transaction
update c
set c.crmnumberAC = a.AccountNumber
--select a.name, a.AccountNumber, c.fullname, c.crmnumberAC
from Contact as c
right join Account as a
on c.PFH_Mapping_Ac_ContacId = a.AccountId
WHERE (a.AccountNumber IS NOT NULL AND c.crmnumberAC IS NULL)
OR a.AccountNumber != c.crmnumberAC
rollback transaction
This is the result set when I uncomment the select and just run that as far as the where;

As you can see, your SELECT doesn't return anything from the table Contact, the table you are trying to UPDATE.
The SELECT returns a row just because you have a right join, but in table Contact you have no row that fulfill the where condition.

Related

How can I perform the Count function with a where clause?

I have my database setup to allow a user to "Like" or "Dislike" a post. If it is liked, the column isliked = true, false otherwise (null if nothing.)
The problem is, I am trying to create a view that shows all Posts, and also shows a column with how many 'likes' and 'dislikes' each post has. Here is my SQL; I'm not sure where to go from here. It's been a while since I've worked with SQL and everything I've tried so far has not given me what I want.
Perhaps my DB isn't setup properly for this. Here is the SQL:
Select trippin.AccountData.username, trippin.PostData.posttext,
trippin.CategoryData.categoryname, Count(trippin.LikesDislikesData.liked)
as TimesLiked from trippin.PostData
inner join trippin.AccountData on trippin.PostData.accountid = trippin.AccountData.id
inner join trippin.CategoryData on trippin.CategoryData.id = trippin.PostData.categoryid
full outer join trippin.LikesDislikesData on trippin.LikesDislikesData.postid =
trippin.PostData.id
full outer join trippin.LikesDislikesData likes2 on trippin.LikesDislikesData.accountid =
trippin.AccountData.id
Group By (trippin.AccountData.username), (trippin.PostData.posttext), (trippin.categorydata.categoryname);
Here's my table setup (I've only included relevant columns):
LikesDislikesData
isliked(bit) || accountid(string) || postid(string
PostData
id(string) || posttext || accountid(string)
AccountData
id(string) || username(string)
CategoryData
categoryname(string)
Problem 1: FULL OUTER JOIN versus LEFT OUTER JOIN. Full outer joins are seldom what you want, it means you want all data specified on the "left" and all data specified on the "right", that are matched and unmatched. What you want is all the PostData on the "left" and any matching Likes data on the "right". If some right hand side rows don't match something on the left, then you don't care about it. Almost always work from left to right and join results that are relevant.
Problem 2: table alias. Where ever you alias a table name - such as Likes2 - then every instance of that table within the query needs to use that alias. Straight after you declare the alias Likes2, your join condition refers back to trippin.LikesDislikesData, which is the first instance of the table. Given the second one in joining on a different field I suspect that the postid and accountid are being matched on the same row, therefore it should be AND together, not a separate table instance. EDIT reading your schema closer, it seems this wouldn't be needed at all.
Problem 3: to solve you Counts problem separate them using CASE statements. Count will add the number of non NULL values returned for each CASE. If the likes.liked = 1, then return 1 otherwise return NULL. The NULL will be returned if the columns contains a 0 or a NULL.
SELECT trippin.PostData.Id, trippin.AccountData.username, trippin.PostData.posttext,
trippin.CategoryData.categoryname,
SUM(CASE WHEN likes.liked = 1 THEN 1 ELSE 0 END) as TimesLiked,
SUM(CASE WHEN likes.liked = 0 THEN 1 ELSE 0 END) as TimesDisLiked
FROM trippin.PostData
INNER JOIN trippin.AccountData ON trippin.PostData.accountid = trippin.AccountData.id
INNER JOIN trippin.CategoryData ON trippin.CategoryData.id = trippin.PostData.categoryid
LEFT OUTER JOIN trippin.LikesDislikesData likes ON likes.postid = trippin.PostData.id
-- remove AND likes.accountid = trippin.AccountData.id
GROUP BY trippin.PostData.Id, (trippin.AccountData.username), (trippin.PostData.posttext), (trippin.categorydata.categoryname);
Then "hide" the PostId column in the User Interface.
Instead of selecting Count(trippin.LikesDislikesData.liked) you could put in a select statement:
Select AccountData.username, PostData.posttext, CategoryData.categoryname,
(select Count(*)
from LikesDislikesData as likes2
where likes2.postid = postdata.id
and likes2.liked = 'like' ) as TimesLiked
from PostData
inner join AccountData on PostData.accountid = AccountData.id
inner join CategoryData on CategoryData.id = PostData.categoryid
USE AdventureWorksDW2008R2
GO
SET NOCOUNT ON
GO
/*
Default
*/
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
GO
BEGIN TRAN
IF OBJECT_ID('tempdb.dbo.#LikesDislikesData') IS NOT NULL
BEGIN
DROP TABLE #LikesDislikesData
END
CREATE TABLE #LikesDislikesData(
isLiked bit
,accountid VARCHAR(50)
,postid VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#PostData') IS NOT NULL
BEGIN
DROP TABLE #PostData
END
CREATE TABLE #PostData(
postid INT IDENTITY(1,1) NOT NULL
,accountid VARCHAR(50)
,posttext VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#AccountData') IS NOT NULL
BEGIN
DROP TABLE #AccountData
END
CREATE TABLE #AccountData(
accountid INT
,username VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#CategoryData') IS NOT NULL
BEGIN
DROP TABLE #CategoryData
END
CREATE TABLE #CategoryData(
categoryname VARCHAR(50)
);
INSERT INTO #AccountData VALUES ('1', 'user1')
INSERT INTO #PostData VALUES('1','this is a post')
INSERT INTO #LikesDislikesData (isLiked ,accountid, postid)
SELECT '1', P.accountid, P.postid
FROM #PostData P
WHERE P.posttext = 'this is a post'
SELECT *
FROM #PostData
SELECT *
FROM #LikesDislikesData
SELECT *
FROM #AccountData
SELECT COUNT(L.isLiked) 'Likes'
,P.posttext
,A.username
FROM #PostData P
JOIN #LikesDislikesData L
ON P.accountid = L.accountid
AND L.IsLiked = 1
JOIN #AccountData A
ON P.accountid = A.accountid
GROUP BY P.posttext, A.username
SELECT X.likes, Y.dislikes
FROM (
(SELECT COUNT(isliked)as 'likes', accountid
FROM #LikesDislikesData
WHERE isLiked = 1
GROUP BY accountid
) X
JOIN
(SELECT COUNT(isliked)as 'dislikes', accountid
FROM #LikesDislikesData
WHERE isLiked = 0
GROUP BY accountid) Y
ON x.accountid = y.accountid)
IF (XACT_STATE() = 1 AND ERROR_STATE() = 0)
BEGIN
COMMIT TRAN
END
ELSE IF (##TRANCOUNT > 0)
BEGIN
ROLLBACK TRAN
END
How do you think about the solution? We create a new table SummaryReport(PostID,AccountID,NumberOfLikedTime,NumberOfDislikedTimes).
An user clicks on LIKE or DISLIKE button we update the table. After that, you can query as you desire. Another advantage, the table can be served reporting purpose.

SQL update with count gets only nulls

I am using SQL Server 2008 R2 and SSRS 2008 to generate the report. I am trying to update a table to get a count of the results from another table.
UPDATE r
SET r.Race = d2.Race,
r.RaceNum = d2.count
FROM #results r
INNER JOIN
(SELECT d.Race,
COUNT(d.race) AS 'count'
FROM #Demographic d
GROUP BY d.Race)d2 ON r.Race = d2.Race
An insert works perfectly but I am inserting several times into the results table to create a demographics report. This is creating a lot Null data at the table of the results. If anyone has an idea of what I am going wrong the help would be appreciated.
Not certain, but first guess is that count is a reserved word... change it to something else such as...
update r
set r.Race = d2.Race, r.RaceNum = d2.cnt
from #results r
inner join
(select d.Race, COUNT(d.race) as 'cnt' from #Demographic d group by d.Race)d2
on r.Race = d2.Race
or alternatively try delimiting the column identifier as [count] or if you have quoted identifiers on "count"
Your query is:
update r
set r.Race = d2.Race, /*<---------*/
r.RaceNum = d2.count
from #results r inner join
(select d.Race, COUNT(d.race) as 'count'
from #Demographic d
group by d.Race
) d2
on r.Race = d2.Race /*<-------- */
The two marked lines stand out. You are joining on values using =, then you are setting one equal to the other. This may not be the problem, but it is suspicious. If you are joining on them, why are you setting them equal? My suspicion is that the join is failing, because nothing matches it.
You don't need to update the race column, since that's the equality portion of your join.
As written, any race not in #demographic would have its racenum set to null. If you want 0 for those try:
UDPATE
r
SET
r.RaceNum = ISNULL(d2.ct, 0)
FROM #results r
LEFT JOIN
(
SELECT
d.Race
, COUNT(d.race) as ct
FROM
#Demographic d
GROUP BY
d.Race
) d2
ON
r.Race = d2.Race

DB2 set default when null on join / Open table after FETCH

This is kind of a double question, just thinking of ways to accomplish my problem.
Also, I'm pretty new to DB2 and stored procedures, so bear with me.
I'm creating a stored procedure that gets a value from two tables using a Left Join statement. This will result in some of the values in the second table returning a null value (since they don't exist in tableB).
DECLARE CURSOR C1 WITH RETURN FOR
select a.name, a.title, b.order from tableA a
left outer join tableB b on a.name = b.name;
Now, I need some way to set these null values to a default value of 0.
The program I'm working with can do it ( CAST-IRON ) but if the result set is too large, it slows down the orchestrations and truncates the job log. So I'm trying to figure it out using the stored procedure.
My first thought was to use the FETCH INTO statement and a WHILE loop.
WHILE AT_END = 0 DO
FETCH C1 INTO CHNAME, CHTITLE, CHORDER;
IF CHORDER IS NULL
THEN SET CHORDER = 0;
END IF;
IF SQLCODE = 100
THEN SET AT_END = 1;
END IF;
END WHILE;
But it seems like that would require a temporary table being created, and declaring another cursor with that table, using an insert command after the 'FETCH INTO'. So I was wondering if there were another way to do this, or to automatically set a default in the select statement?
Set a default in the select statement using COALESCE.
DECLARE CURSOR C1 WITH RETURN FOR
select a.name, a.title, COALESCE(b.order,0) as order
from tableA a
left outer join tableB b on a.name = b.name;

SQL Having Clause

I'm trying to get a stored procedure to work using the following syntax:
select count(sl.Item_Number)
as NumOccurrences
from spv3SalesDocument as sd
left outer join spv3saleslineitem as sl on sd.Sales_Doc_Type = sl.Sales_Doc_Type and
sd.Sales_Doc_Num = sl.Sales_Doc_Num
where
sd.Sales_Doc_Type='ORDER' and
sd.Sales_Doc_Num='OREQP0000170' and
sl.Item_Number = 'MCN-USF'
group by
sl.Item_Number
having count (distinct sl.Item_Number) = 0
In this particular case when the criteria is not met the query returns no records and the 'count' is just blank. I need a 0 returned so that I can apply a condition instead of just nothing.
I'm guessing it is a fairly simple fix but beyond my simple brain capacity.
Any help is greatly appreciated.
Wally
First, having a specific where clause on sl defeats the purpose of the left outer join -- it bascially turns it into an inner join.
It sounds like you are trying to return 0 if there are no matches. I'm a T-SQL programmer, so I don't know if this will be meaningful in other flavors... and I don't know enough about the context for this query, but it sounds like you are trying to use this query for branching in an IF statement... perhaps this will help you on your way, even if it is not quite what you're looking for...
IF NOT EXISTS (SELECT 1 FROM spv3SalesDocument as sd
INNER JOINs pv3saleslineitem as sl on sd.Sales_Doc_Type = sl.Sales_Doc_Type
and sd.Sales_Doc_Num = sl.Sales_Doc_Num
WHERE sd.Sales_Doc_Type='ORDER'
and sd.Sales_Doc_Num='OREQP0000170'
and sl.Item_Number = 'MCN-USF')
BEGIN
-- Do something...
END
I didn't test these but off the top of my head give them a try:
select ISNULL(count(sl.Item_Number), 0) as NumOccurrences
If that one doesn't work, try this one:
select
CASE count(sl.Item_Number)
WHEN NULL THEN 0
WHEN '' THEN 0
ELSE count(sl.Item_Number)
END as NumOccurrences
This combination of group by and having looks pretty suspicious:
group by sl.Item_Number
having count (distinct sl.Item_Number) = 0
I'd expect this having condition to approve only groups were Item_Number is null.
To always return a row, use a union. For example:
select name, count(*) as CustomerCount
from customers
group by
name
having count(*) > 1
union all
select 'No one found!', 0
where not exists
(
select *
from customers
group by
name
having count(*) > 1
)

How can I select none duplicate rows with inner join?

My MS SQL Server stored procedure is:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_close]
#DATE NVARCHAR(8)
AS
BEGIN
SELECT appointment_datas.appointment_date
,appointment_datas.appointment_no
,costumer_datas.costumer_name
,appointment_datas.appointment_type
,personel_datas.personel_ADI
FROM [LONI].[dbo].appointment_datas
INNER JOIN [LONI].[dbo].costumer_datas ON appointment_datas.appointment_costumer = costumer_datas.costumer_id
INNER JOIN [LONI].[dbo].personel_datas ON appointment_datas.appointment_personel = personel_datas.personel_id
INNER JOIN [GUONU].[dbo].dayend ON appointment_datas.appointment_no <> dayend.appointment_no COLLATE Turkish_CI_AS
WHERE CONVERT(nvarchar(8),appointment_datas.appointment_date,112) = #DATE
END
With this code, I select duplicate rows from the same records. Actually I want to select fields from [LONI].[dbo].appointment_datas but if appointment_no
is not in [GUONU].[dbo].dayend
SELECT DISTINCT removes duplicates in your output.
But your SQL looks wrong. Are you sure you mean to write:
TABLE1.FIELD1 <> TABLE1.FIELD1
This always evaulates to false. I think you may have an error in your SQL, and that might be why you are getting duplicate values. You should rarely use <> in a join clause, and you shouldn't have the same field on both sides.
Maybe you intended:
ON [DB1].[dbo].TABLE1.FIELD1 <> [DB2].[dbo].TABLE1.FIELD1
but this will generate a Cartesian product of all the rows that don't match. I doubt this is what you really mean. Perhaps you want this:
ON [DB1].[dbo].TABLE1.ID = [DB2].[dbo].TABLE1.ID
WHERE[DB1].[dbo].TABLE1.FIELD1 <> [DB2].[dbo].TABLE1.FIELD1
This matches the rows from each database that have the same ID, but differ in a certain column. Notice that the <> is not in the JOIN clause.
--- UPDATE ---
Perhaps you mean to select the results from the two different databases and then union them?
SELECT appointment_datas.appointment_date
,appointment_datas.appointment_no
,costumer_datas.costumer_name
,appointment_datas.appointment_type
,personel_datas.personel_ADI
FROM [LONI].[dbo].appointment_datas
INNER JOIN [LONI].[dbo].costumer_datas ON appointment_datas.appointment_costumer = costumer_datas.costumer_id
INNER JOIN [LONI].[dbo].personel_datas ON appointment_datas.appointment_personel = personel_datas.personel_id
WHERE CONVERT(nvarchar(8),appointment_datas.appointment_date,112)
UNION
SELECT appointment_datas.appointment_date
,appointment_datas.appointment_no
,costumer_datas.costumer_name
,appointment_datas.appointment_type
,personel_datas.personel_ADI
FROM [GUONU].[dbo].appointment_datas
INNER JOIN [GUONU].[dbo].costumer_datas ON appointment_datas.appointment_costumer = costumer_datas.costumer_id
INNER JOIN [GUONU].[dbo].personel_datas ON appointment_datas.appointment_personel = personel_datas.personel_id
WHERE CONVERT(nvarchar(8),appointment_datas.appointment_date,112)
--- SOLUTION ---
Use NOT EXISTS in WHERE clause. Read comments to see why.
The line
INNER JOIN [DB2].[dbo].TABLE1 ON TABLE1.FIELD1 <> TABLE1.FIELD1
makes no sense, you want to rephrase that...
If I understand your question correctly (after your edit)
but if appointment_no is not in
[GUONU].[dbo].dayend
, you actually want a NOT EXISTS subquery:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_close]
#DATE NVARCHAR(8)
AS
BEGIN
SELECT appointment_datas.appointment_date
,appointment_datas.appointment_no
,costumer_datas.costumer_name
,appointment_datas.appointment_type
,personel_datas.personel_ADI
FROM [LONI].[dbo].appointment_datas
INNER JOIN [LONI].[dbo].costumer_datas ON appointment_datas.appointment_costumer = costumer_datas.costumer_id
INNER JOIN [LONI].[dbo].personel_datas ON appointment_datas.appointment_personel = personel_datas.personel_id
WHERE CONVERT(nvarchar(8),appointment_datas.appointment_date,112) = #DATE
AND NOT EXISTS (SELECT 'X' FROM [GUONU].[dbo].dayend WHERE dayend.appointment_no = appointment_datas.appointment_no)
END
SELECT DISTINCT TABLE1.FIELD1
,TABLE2.FIELD1
,TABLE1.FIELD3
,TABLE3.FIELD1
FROM ...
NB in some variants you will have to bracket the field list ie
SELECT DISTINCT (TABLE1.FIELD1
,TABLE2.FIELD1
,TABLE1.FIELD3
,TABLE3.FIELD1 ) FROM ...