I am trying to update a data type in the table I work with. It currently is stored as an int but it really is a date column.
It looks like 20191012 right now. For some reason instead of using null, they had columns with no dates be 0.
When I query the table I use
case
when bthdat = 0
then '9999-12-31'
else convert(date, convert(varchar(10), bthdat)) as dob
end
Can I use the same logic to update the actual table itself? If so, how? Thanks.
You're not going to be able to UPDATE your existing column, as int and date aren't compatible.
What you can do, however, is change the datatype a couple of times, with an UPDATE in the middle. This, however, assumes that all the values are valid (for example don't have a value like 20190229) and in the ISO format yyyyMMdd
ALTER TABLE dbo.YourTable ALTER COLUMN bthdat varchar(10);
UPDATE dbo.YourTable
SET bthdat = NULL
WHERE bthdat = '0';
ALTER TABLE dbo.YourTable ALTER COLUMN bthdat date;
You can use as follows
update
a
set
bthdat = case
when bthdat = 0 then '9999-12-31'
else convert(date,convert(varchar(10),bthdat))
end
from
YourTable as a
Do not forget to set the else for records that are not updated to keep the existing value.
Related
I have an update statement to update some values for a table, but made a mistake. How can I roll this back?
The query I ran is this:
update t1
set t1.[DateAdded] = case
when t1.[DateAdded] is null
then cast(getdate() as date)
end
from [PEA].[pc].[TPC_Participants_Record_STG] as t1;
go
You might get away with the following update:
UPDATE [PEA].[pc].[TPC_Participants_Record_STG]
SET DateAdded = NULL
WHERE DateAdded = CAST(GETDATE() AS date);
But note carefully that the above assumes that before your erroneous update no records already had a DateAdded value with today's date. If not, then the above would be nulling out some possibly valid data which should not change.
I want to create trigger which after insert longitude and latitude to table Vehicle create point from longitude latitude.
My trigger looks that
create trigger [dbo].[t_points]
on [dbo].[Vehicle]
after insert
as
begin
SET NOCOUNT ON;
DECLARE #Point AS GEOGRAPHY
DECLARE #Longitude AS FLOAT
DECLARE #Latitude AS FLOAT
set #latitude = (select v.latitude from Vehicle v)
set #longitude = (select v.longitude from Vehicle v)
if #latitude is not null and #Longitude is not null
begin
set #Point = geography::Point(#latitude,#longitude,4326)
update Vehicle set locationVehicle = #Point
end
end
GO
but when I insert to my table values:
insert into Vehicle
(idGroupVehicle, brand, model, maxRange, weight, maxSpeed, pricePerSale,
latitude, longitude, locationName)
values ('1', 'Xiaomi', 'Mijia M365 PRO', '45', '14', '1900', '25',
'19.905203', '50.071597', 'Piastowska 49 Kraków')
I have error
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Can someone explain me why I have this error and I can't insert to my table this value my trigger only check is latitude and longitude is not null create a point.
You must query the Inserted pseudo table to get the inserted rows inside an insert trigger. This table might return several rows. Instead of looping through the rows, you can update the location column like this
CREATE TRIGGER [dbo].[t_points]
ON [dbo].[Vehicle]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE v
SET
v.locationVehicle = geography::Point(i.latitude, i.longitude, 4326)
FROM
dbo.Vehicle v
INNER JOIN inserted i
ON v.idVehicle = i.idVehicle
WHERE
i.latitude IS NOT NULL AND
i.longitude IS NOT NULL
END
Assuming that idGroupVehicle is the primary key of the table. If it is not, replace it by the primary key (every table should have a primary key).
UPDATE According to your comment I replaced idGroupVehicle by idVehicle in the join.
Your trigger has fundamental flaws:
It does not take into account that there might be multiple (or no) rows in the statement
It is not referencing the inserted pseudo-table, so the data it is pulling is from a random row
It is writing back to the whole table, as there is no where filter
Instead a trigger would look like this:
create trigger [dbo].[t_points]
on [dbo].[Vehicle]
after insert
as
SET NOCOUNT ON;
UPDATE v
SET locationVehicle = geography::Point(i.latitude, i.longitude,4326)
FROM inserted i
JOIN v ON v.id = i.id; -- or whatever the primary key is
GO
However:
A much better solution is a simple computed column:
ALTER TABLE Vehicle
ADD locationVehicle AS (geography::Point(latitude, longitude, 4326));
Your issue is, I believe, the way you are expecting triggers to work.
The error you are receiving is nothing to to with the trigger itself, you are declaring a variable and then trying to assign that variable a value from a sub query.
select v.latitude from Vehicle v - this does exactly what you might expect it to, being inside a "trigger" makes no difference, it will return a set of values, all rows in fact from table vehicle - hence the error "returned more than one row" - assigning a value to a variable expects a single value.
To do this with a trigger there is no need to assign values to any variables. What makes a trigger special is it makes available two virtual tables called inserted and deleted that contain rows affected only by the data modification that happened. Your insert could have inserted a single row or many, or none, and only these row(s) will be in the inserted table.
To update your column only for rows affected you would do the following
update v set
v.LocationVehicle=geography::Point(v.latitude,v.longitude,4326)
from inserted i join Vehicle v on v.idGroupVehicle=i.idGroupVehicle
Having said that, you could try using a computed column instead which would accomplish the same thing
Alter table Vehicle add LocationVehicle as geography::Point(latitude,longitude,4326)
I am trying to populate a column based on a certain condition when the table is updated with new rows using trigger.
Here is what I wrote.
create trigger [myschema].[charD]
on [myschema].[deposits]
after update
as
begin
set nocount on;
update myschema.deposits
set dayC = (convert(varchar, day, 23))
from myschema.deposits
where dayC is null
end
GO
This doesn't update or populate the column dayC when new rows are added, what am I missing here?
set dayC = (convert(varchar, day, 23))
Looks like you are converting / formatting a date or datetime to string in YYYY-MM-DD format
Instead of using trigger, you can use a computed column
ALTER TABLE [myschema].[deposits]
ADD [dayc] AS CONVERT(VARCHAR(10), [day], 23)
You need to change it to after insert
Also you have no correlation to the inserted table.
You need to join with inserted on your PK to update the inserted rows, otherwise you are updating all rows in your table every time.
use-the-inserted-and-deleted-tables
I'm trying to add a calculated field to an existing table in SSMS, which will convert a string in the format YYYYMMDD to a date format, but I am getting errors regarding the string field not being valid.
I require the calculated field as I have '00000000' values (i.e. NULL) in the string field so can't use this in date calculations.
The code I'm using is :
ALTER TABLE [TEM].[AssignmentRates]
ADD [Date_Expired] DATE NULL
(SELECT CONVERT([date], CASE WHEN [Expiry_Date]='00000000' THEN NULL ELSE [Expiry_Date] END))
where [Expiry_Date] is the string column I'm trying to convert, and [Date_Expired] is the name of the calculated column I'm trying to add.
I get this error:
Invalid column name 'Expiry_Date'
against both instances of that field name, and can't work out why. If I run the query as a stand alone SELECT it returns the required results.
Using table aliases or the full database, table and column name for it don't appear to work either.
It's probably something incredibly obvious, but I haven't been able to work out what it is.
The error on expiry_date seems quite clear -- that is not the name of a column in the table. But you can simplify the logic:
ALTER TABLE TEM.AssignmentRates ADD Date_Expired AS
(TRY_CONVERT(date, Expiry_Date));
Actually, the nested SELECT may have caused an issue. That would not normally be used for a computed column.
Looks like a syntax issue
alter table [TEM].[AssignmentRates]
ADD [Date_Expired]
as
(
case Expiry_Date when '00000000' then null else cast(Expiry_Date as date) end
)
Your syntax was invalid for a computed column. What you had was actually adding a regular column (successfully) but then the attempting to run a select statement which was causing those column-name errors as it didn't have a from clause for context.
ALTER TABLE TEM.AssignmentRates /* don't do this */
ADD Date_Expired DATE NULL /* implied end of statement */
(SELECT CONVERT(date, CASE WHEN Expiry_Date = '00000000' THEN NULL ELSE Expiry_Date END));
Had you used the proper syntax, you'd at least get an informative error:
ALTER TABLE TEM.AssignmentRates /* error! */
ADD Date_Expired AS
(SELECT CONVERT(date, CASE WHEN Expiry_Date = '00000000' THEN NULL ELSE Expiry_Date END);
/*ERROR: Subqueries are not allowed in this context. Only scalar expressions are allowed.*/
But really you didn't need a subquery in the first place:
ALTER TABLE TEM.AssignmentRates /* success */
ADD Date_Expired AS
CONVERT(date, CASE WHEN Expiry_Date = '00000000' THEN NULL ELSE Expiry_Date END);
Gordon has a point about just using try_convert() though.
I have a database in SQL Server with its data. I need change a part of some columns value in some conditions.
Imagine the value as "0010020001".
002 belongs to another value in my database and whenever I want to change it to 005, I must update the previous 10-digits code to "001005001".
Actually, I need to update just a part of columns value using UPDATE statement. How can I do it (in this example)?
While everyone else is correct that if you have control of the schema you should definitely not store your data this way, this is how I would solve the issue you as you described it if I couldn't adjust the schema.
IF OBJECT_ID('tempdb..#test') IS NOT NULL
DROP TABLE #test
create table #test
(
id int,
multivaluecolumn varchar(20)
)
insert #Test
select 1,'001002001'
UNION
select 2,'002004002'
UNION
select 3,'003006003'
GO
declare #oldmiddlevalue char(3)
set #oldmiddlevalue= '002'
declare #newmiddlevalue char(3)
set #newmiddlevalue = '005'
select * from #Test
Update #Test set multivaluecolumn =left(multivaluecolumn,3) + #newmiddlevalue + right(multivaluecolumn,3)
where substring(multivaluecolumn,4,3) = #oldmiddlevalue
select * from #Test
Why dont you use CSV(comma separated values) or use any other symbol like ~ to store tha values. Once you need to update a part of it use php explode function and then update it. After your work is done, concat all the values again to get the desired string to be stored in your column.
In that case your column will have values VARCHAR like 001~002~0001