cannot insert value NULL into column error shows wrong column name - sql

I've added a new column(NewValue) to my table which holds an int and allows nulls. Now I want to update the column but my insert statement only attempts to update the first column in the table not the one I specified.
I basically start with a temp table that I put my initial data into and it has two columns like this:
create table #tempTable
(
OldValue int,
NewValue int
)
I then do an insert into that table and based on the information NewValue can be null.
Example data in #tempTable:
OldValue NewValue
-------- --------
34556 8765432
34557 7654321
34558 null
Once that's complete I planned to insert NewValue into the primary table like so:
insert into myPrimaryTable(NewValue)
select tt.NewValue from #tempTable tt
left join myPrimaryTable mpt on mpt.Id = tt.OldValue
where tt.NewValue is not null
I only want the NewValue to insert into rows in myPrimaryTable where the Id matches the OldValue. However when I try to execute this code I get the following error:
Cannot insert the value NULL into column 'myCode', table 'myPrimaryTable'; column does not allow nulls. INSERT fails.
But I'm not trying to insert into 'myCode', I specified 'NewValue' as the column but it doesn't seem to see it. I've checked NewValue and it is set to allow int and is set to allow null and it does exist on the right table in the right database. The column 'myCode' is actually the second column in the table. Could someone please point me in the right direction with this error?
Thanks in advance.

INSERT always creates new rows, it never modifies existing rows. If you skip specifying a value for a column in an INSERT and that column has no DEFAULT bound to it and is not identity, that column will be NULL in the new row--thus your error. I believe you might be looking for an UPDATE instead of an INSERT.
Here's a potential query that might work for you:
UPDATE mpt
SET
mpt.NewValue = tt.NewValue
FROM
myPrimaryTable mpt
INNER JOIN #tempTable tt
ON mpt.Id = tt.OldValue -- really?
WHERE
tt.NewValue IS NOT NULL;
Note that I changed it to an INNER JOIN. A LEFT JOIN is clearly incorrect since you are filtering #tempTable for only rows with values, and don't want to update mpt where there is no match to tt--so LEFT JOIN expresses the wrong logical join type.
I put "really?" as a comment on the ON clause since I was wondering if OldValue is really an Id. It probably is--you know your table best. It just raised a mild red flag in my mind to see an Id column being compared to a column that does not have Id in its name (so if it is correct, I would suggest OldId as a better column choice than OldValue).
Also, I recommend that you never name a column just Id again--column names should be the same in every table in the database. Also, when it comes join time you will be more likely to make mistakes when your columns from different tables can coincide. It is much better to follow the format of SomethingId in the Something table, instead of just Id. Correspondingly, the suggested old column name would be OldSomethingId.

Related

Updating or inserting SQL Server destination table data based on conditions from source table data

I have two SQL Server tables, one is my destination table (LocaleStringResource), the other one is the source table (TempResourceSunil).
Source table has the following columns: TempResourceSunil
[ID], [LanguageId], [ResourceName], [ResourceValue], [Burmese], [Unicode]
and the destination table's columns are LocaleStringResource
[Id], [LanguageId], [ResourceName], [ResourceValue]
I want to update the destination table [ResourceValue] based on [ResourceName] from the source file.
Example:
[ResourceName] = 'Account.AccountActivation'
means I want to check it have corresponding Burmese [ResourceValue] in LocaleStringResource table if it does not exist, I will take it from TempResourceSunil and Burmese column and insert it into LocaleStringResource with language id =2.
Same if [ResourceValue] for Unicode (language id = 3) does not exist for [ResourceName] = 'Account.AccountActivation' means I want to insert [ResourceValue] from TempResourceSunil with language id = 3.
Can any SQL expert help me?
The description you gave isn't really fleshed out however, you want to use a Case Statement. CASE STATEMENT INFO
A case statement can have multiple WHENs to cover multiple logic statements. You can even have one inside the other. I wouldn't really do that for this situation.
The example below is just a simple version.
If l.[ResourceValue] is null and l.[ResourceName] = 'Account.AccountActivation' then use the value of T.[Burmese] for column l.[ResourceValue]. ELSE means if no When within the case statement is true, then use this value.
Also be aware that if you are trying to use an INT value from the first table in a string column on the 2nd, you need to cast it as a varchar.
Test out your logic and case statements and see how you get on.
SELECT
l.[Id],
l.[LanguageId],
l.[ResourceName],
CASE WHEN l.[ResourceName] = 'Account.AccountActivation' and l.[ResourceValue] is null then T.[Burmese]
else l.[ResourceValue] end as [ResourceValue],
T.[ID],
T.[LanguageId],
T.[ResourceName],
T.[ResourceValue],
T.[Burmese],
T.[Unicode]
FROM LocaleStringResource as L
LEFT JOIN TempResourceSunil t on (t.ID = L.ID) and (t.[LanguageId] = l.[LanguageId])

Matrix table index SQL Server 2008

I have a table with two columns built from another table of names, one identity and one a name like this:
ID---Name
1----Mike
2----Jeff
3----Robert
...down to however many
Could be 10 rows, could be 100. This will vary depending on input from other tables that are always changing but never be over 160 or so.
Now, pairings of names will have some meaning and thus a decimal data type score will be associated with said pairing (how at this point doesn’t matter, just need to build it for now...numbers just illustrative). I envision a matrix kind of like this:
ID------Name------Mike-------Jeff--------Robert-------- ...out to however many
1 -------Mike-------NULL------100.1------5.4-------- ...out to however many
2 -------Jeff---------100.1------NULL-----21.23--------- ...out to however many
3 ------Robert-------5.4--------21.23-----NULL---------...out to however many
…down to however many happen to be in the first table…
Maybe this isn’t quite the most optimal way to go (Yes, I know there are duplicates in the table but I plan to structure the queries such that the duplicates are ignored) but at this point am not aware of many viable options. After searching around, I thought maybe I wanted a pivot but that doesn’t seem to fit what I have here because I’m leaving the names in the column and associating them as column heads for a paired score. Then I thought maybe I wanted to store a variable as the value of each row and then add them as the columns. That was no help. My latest iteration was maybe creating a temp table as an exact copy with and identity column, then trying to select the specific name by the identity and looping through them but I can’t even seem to grab the first name and make it a column name in addition to a row value under the name column...see below
--create a table of names with an identity column
CREATE TABLE myTable2
(
ID INT IDENTITY(1,1),
Name VARCHAR(5),
);
--add names to the table from a different table
INSERT INTO myTable1 (Name)
SELECT Name
FROM myTable1
--create a temp table with the same values
SELECT ID, Name
INTO #new
FROM myTable2
GROUP BY ID, Name
--insert name from first row as a column head
INSERT INTO myTable2 (SELECT Number FROM #new WHERE ID =1)
So, in the last bit there, INSERT INTO”, I want to copy the names, in this instance “Mike” and make it ALSO a column head in the same table where it is a row (like in my second table). I get an error message that the syntax is not correct for the statement. Why isn’t this allowed? How can I get it to do what I want? It also has been suggested by someone that knows way more about this stuff than me, that maybe instead of building the table as a matrix, build it as below. It is possible here to get rid of the duplicates this way and I would except I have no idea where to even begin doing this…
Name1-----------Name2-----------Calculated Value
Mike--------------Mike-------------NULL
Jeff---------------Mike-------------100.1
Robert-------------Mike-------------5.4
Mike--------------Jeff-------------100.1
Jeff----------------Jeff-------------NULL
Robert------------Jeff-------------21.23
Mike--------------Robert-----------5.4
Jeff---------------Robert-----------21.23
Robert------------Robert-----------NULL
...etc
Any help suggestions or pointing of me in the right and most appropriate direction would be greatly appreciated!
EDIT: Here's how I solved my problem. Looks like the Cartesian product was the way to go. Thanks #Alex Kudryashev
--create a table of cross joined names
CREATE TABLE cartNames
(
Name1 VARCHAR(5),
Name2 VARCHAR(5),
);
--create two temporary tables from a source table of names
SELECT Name AS Name1
INTO #name1
FROM names
GROUP BY Name
SELECT Name AS Name2
INTO #Name2
FROM names
GROUP BY Name
--populate the Cartesian table
INSERT INTO cartNames
SELECT * FROM #name1 CROSS JOIN #name2
--get rid of the temp tables
DROP TABLE #Name1
DROP TABLE #Name2
--add columns and populate calculated scores
---
It looks like you want to create a Cartesian Product. There is very easy way to do so.
declare #tbl table(name varchar(10))
insert #tbl(name) values('MIke'),('Jeff'),('Robert')
select t1.name name1,t2.name name2, some_udf(t1.name,t2.name) calc_value
from #tbl t1 cross join #tbl t2

Checking if ID exists and also if another column is null and updating another column

I am about to implement an update statement on a table. I know it sounds really simple, but I'm not able to get through it logically.
Scenario:
There is a table I have with the below format, that gets data everyday through a process. The columns on the table are as follows:
PKID | RecordID | ThirdPartyID | Action | DATEADDED
PKID: The auto incremental Primary Key.
RecordID: Can have duplicates.
ThirdpartyID: Can be multiple values and also accepts NULLS.
Action: The column that needs to be updated
DateAdded: Contains the GETDATE() of when the record is imported into the table.
Problem:
There is a process that imports new records into this table everyday. When the records are inserted for a day, I need to check the following:
Check if the newly Inserted RecordIDs are already existing in the table.
If the RecordID entered today, is already there in the table (there can be multiple entries of the same RecordID in the old records),
Check if the ThirdPartyID is NULL in the old records for that RecordID.
If the ThirdPartyID exists in any of the old records for that RecordID, update the Action Column with 'Multiple Entries.'
Else do nothing.
Please let me know if I can provide any further clarification or details in this regard.
I would approach the problem like this:
Load new data into a Temp table.
Inner Join the 2 tables on RecordID which will join only if the RecordID exists in both tables...
update the Action column to "Multiple Entries" if the ThirdPartyID field is also null.
Script should be something like this:
UPDATE Main
SET Action = 'Multiple Entries'
FROM Main INNER JOIN Temp ON Main.RecordID = Temp.RecordID
WHERE Main.ThirdPartyID IS NOT NULL
You could get a copy of the inserted data by OUTPUT-ing it to a table variable, then perform the update by joining to the original table. e.g:
DECLARE #inserted TABLE
(PKID INT
,RecordID INT
,ThirdPartyID INT
,Action VARCHAR(MAX)
,DateAdded DATE);
INSERT TestTable1
(RecordID
,ThirdPartyID
,Action
,DateAdded)
OUTPUT
inserted.PKID
,inserted.RecordID
,inserted.ThirdPartyID
,inserted.Action
,inserted.DateAdded
INTO #inserted
(PKID
,RecordID
,ThirdPartyID
,Action
,DateAdded)
VALUES
(1
,2
,NULL
,GETDATE());
UPDATE t
SET ThirdPartyID = 'Multiple Entries'
FROM #inserted i
JOIN TestTable1 t
ON i.RecordID = t.RecordID
WHERE t.ThirdPartyID IS NOT NULL;

SQL all data from table one some data from table 2

Probably a dumb question: buts I've spent enough hours that I really need some outside help.
I have one table that has a list of names: some of thse sames may not be in table two and I need all names listed.
In a second table I have the some of same names, but these names can be listed with an event date and an event type.
How would I list all the names from table one.
And also include the events from table two given specific event types.
This means that is a name in table one is not linked to an event in table two it will still print.
I have tried left outer join: but cannot still figure out how to limit the data coming from table two: or if I place a where clause the where clause seems to nullify adding all names from table 1 because they do not meet the parameters I place on table 2.
For SQL Server my suggestion is something like this:
CREATE TABLE tblNames(
Name NVARCHAR(MAX) NOT NULL)
GO
INSERT INTO tblNames (Name) VALUES ('Jim'), ('Jack'), ('Joe')
GO
CREATE TABLE tblEvents(
Name NVARCHAR(MAX) NOT NULL,
EventDate NVARCHAR(max) NOT NULL,
EventType NVARCHAR(max) NOT NULL)
GO
INSERT INTO tblEvents (Name, EventDate, EventType) VALUES
('Jim', '04/05/2000', 'Birthday'),
('Joe', '01/01/1999', 'Marriage')
GO
SELECT
tblNames.Name,
tblEvents.EventDate,
tblEvents.EventType
FROM tblNames
LEFT OUTER JOIN tblEvents
ON tblNames.Name = tblEvents.Name
AND tblEvents.EventType = 'Birthday'
It will give you all the Names in column Names and if there is a entry in tblEvents with the matching event type you'll have that info in the other columns.

Look Up Table in SQL

I basically have a table A with 30 million records and I want to add a column entitled "TYPE" to the table. I have a look up table B that maps a code to a color. I want to iterate through table A and compare the code in TABLE A to the code in TABLE B and then add the color to the TYPE column in table A. Is this possible? What would be the best approach to this problem? The codes in table B don't match perfectly with the actual codes in table A.
hard to say without seeing the schema or knowing the DBMS but, if it's always a the first 2 digits of the code used to look up the color, why not
UPDATE table_a SET type = SUBSTR(code, 2)
and do a JOIN normally
you could do a join like
JOIN table_b ON table_b.id = SUBSTR(table_a.code,2)
but that would hardly be performant.
Give or take issues with size of transaction, isn't it a simple ALTER TABLE to add the column and an UPDATE to fix it?
ALTER TABLE TableA ADD (Type VARCHAR(10));
UPDATE TableA
SET Type = ((SELECT Colour FROM TableB WHERE TableA.Type = TableB.Type));
The only tricky bit might be the double parentheses; they're needed in some DBMS and may not be needed in others (single parentheses may be sufficient). You may also be able to use a UPDATE with a JOIN; the syntax isn't entirely standard there, either.
Note that this mapping relies on a change of NULL to NULL being a no-op. If you have values in some rows but not all of those rows match an entry in TableB, then you need to be careful with an full-table UPDATE like that. It will set the Type for any rows in TableA for which there is no match in TableB to NULL. If that wasn't what you needed, you'd either use an UPDATE with JOIN or you'd write:
UPDATE TableA
SET Type = ((SELECT Colour FROM TableB WHERE TableA.Type = TableB.Type));
WHERE Type IN (SELECT Colour FROM TableB WHERE TableA.Type = TableB.Type);
In the current case, where the column is newly added and therefore contains NULL anyway, there is no harm done omitting the WHERE clause on the UPDATE itself.
You can do the update just by looking at the first characters of the code in table B, as in the following statement:
update table_a
set table_a.type = table_b.type
from table_b
where table_b.code = substr(table_a.code, 1, length(table_b.code))
This may be a bit slow, since you cannot use any indexes to speed it up. However, if table_b is small, then the performance may be acceptable.