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
Related
I have 2 tables (A and B). I want to implement such logic to table B:
[Bank] AS (iif( Some_Statement,
(SELECT [Money] FROM [ATM] WHERE [B].[Currency] = [A].[Currency] ),
[NoMoney]
)
)
I get an error: Subqueries are not allowed in this context. Only scalar expressions are allowed.
Is there a way to implement such logic on creation of the tables? It doesn't look hard.
After reading the discussion in comments I get the feeling, that this was going the wrong direction. Might be because of your very direct question about IIF()...
If I get this correctly you try to add a computed column to you table. Something along this:
DECLARE #tblTest TABLE (ID INT IDENTITY
,SomeValue VARCHAR(100)
,[Test] AS IIF(SomeValue IS NOT NULL, CONCAT(SomeValue,'Blah'), 'Default if null'));
INSERT INTO #tblTest(SomeValue) VALUES('Test');
INSERT INTO #tblTest(SomeValue) VALUES(NULL);
SELECT * FROM #tblTest;
The result
ID SomeValue Test
1 Test TestBlah
2 NULL Default if null
Now you want to get the value for the computed column not just from some simple scalar computation, but you want to pick it from a table.
Here I will try to simulate your issue. Next time it is up to you to do this yourself. Providing DDL, sample data and the expected output together with your own attempts is the best chance to get the answer you are waiting for.
This is the table B from where you want to get the value.
Later we will ask for 'Test' and not for 'xyz'.
CREATE TABLE tblB (ID INT IDENTITY
,SomeResultColumn VARCHAR(100)
,SomeConditionColumn VARCHAR(100));
INSERT INTO tblB(SomeResultColumn,SomeConditionColumn) VALUES('not wanted','xyz')
,('wanted','Test');
GO
--This is what you are trying to do, but I out-commented it because of the error you've got.
--A computed column does not allow for a SELECT. This is not bound to the IIF()
--CREATE TABLE tblA (ID INT IDENTITY
-- ,SomeValue VARCHAR(100)
-- ,[Test] AS IIF(SomeValue IS NOT NULL,(SELECT b.SomeResultColumn FROM tblB b WHERE b.SomeConditionColumn=SomeValue),'Default if null'));
--GO
--But what we can do - and the error message is telling so - provide a scalar expression:
--A Scalar Function is exactly this:
CREATE FUNCTION dbo.GetMyComputedColumn(#Condition VARCHAR(100))
RETURNS VARCHAR(100) AS
BEGIN
RETURN (SELECT b.SomeResultColumn --You might use `TOP 1` to ensure a scalar result
FROM tblB b
WHERE b.SomeConditionColumn=#Condition);
END
GO
--We can use this function in the IIF():
CREATE TABLE tblA (ID INT IDENTITY
,SomeValue VARCHAR(100)
,[Test] AS IIF(SomeValue IS NOT NULL,dbo.GetMyComputedColumn(SomeValue),'Default if null'));
GO
INSERT INTO tblA(SomeValue) VALUES('Test');
INSERT INTO tblA(SomeValue) VALUES(NULL);
SELECT * FROM tblA;
The result
ID SomeValue Test
1 Test wanted
2 NULL Default if null
Should you do this?
The question, if this is a good idea, is something completely different.
Besides the fact, that scalar functions are known as bad performers, the main question is: WHY?
Do you need a persistant default value? In this case a trigger will be a better choice... Or you can use an insert statement with the computed value directly. I'm afraid you are mixing the concepts of computed columns and a default constraint. The computed column cannot be changed...
If you want to compute this value whenever you fetch data from this table, it was much better to use a VIEW or an iTVF, where you simply join the needed value to your result set.
If what you are saying is that you want a value from table "B" IF it matches on a value from your main table "A" and if there is no matching value in "B", use a literal as a default, try this:
select
Bank,
coalesce( (SELECT Money FROM ATM WHERE Currency = A.Currency), 'NoMoney' ) as 'Type'
from
ATM A
where
....
If the select of [Money] returns null, the literal 'NoMoney' will be used.
If need be, you can have a select on both sides of the coalesce, the right need not be a literal.
I have a table with a populated column of type binary(24). I want to increase this field length to binary(32). This part's easy enough. The problem I'm running into is when I try to query the table based on that field's previous value. (We were using a hashbytes function).
So BEFORE the field length increase, I could just use:
SELECT * FROM Table WHERE Field = HASHBYTES('md5', 'value')
AFTER the field length increase, this query returns nothing. How would I change the query to return the appropriate value? What can I add on to the end of the binary in order for it to be recognized?
Thanks!
Edit: I've apparently done something ELSE wrong, as this works fine.
CREATE TABLE #test (test binary(24) null)
insert into #test (test) values (hashbytes('md5', 'test'))
select * from #test
ALTER TABLE #test ALTER COLUMN test binary(32) null
select * from #test where test = hashbytes('md5', 'test')
drop table #test
Could you use CONVERT in the WHERE to turn it back into binary(24) ?
CONVERT binary
I need to know if there is any way to have a SEQUENCE or something like that, as we have in Oracle. The idea is to get one number and then use it as a key to save some records in a table. Each time we need to save data in that table, first we get the next number from the sequence and then we use the same to save some records. Is not an IDENTITY column.
For example:
[ID] [SEQUENCE ID] [Code] [Value]
1 1 A 232
2 1 B 454
3 1 C 565
Next time someone needs to add records, the next SEQUENCE ID should be 2, is there any way to do it? the sequence could be a guid for me as well.
As Guillelon points out, the best way to do this in SQL Server is with an identity column.
You can simply define a column as being identity. When a new row is inserted, the identity is automatically incremented.
The difference is that the identity is updated on every row, not just some rows. To be honest, think this is a much better approach. Your example suggests that you are storing both an entity and detail in the same table.
The SequenceId should be the primary identity key in another table. This value can then be used for insertion into this table.
This can be done using multiple ways, Following is what I can think of
Creating a trigger and there by computing the possible value
Adding a computed column along with a function that retrieves the next value of the sequence
Here is an article that presents various solutions
One possible way is to do something like this:
-- Example 1
DECLARE #Var INT
SET #Var = Select Max(ID) + 1 From tbl;
INSERT INTO tbl VALUES (#var,'Record 1')
INSERT INTO tbl VALUES (#var,'Record 2')
INSERT INTO tbl VALUES (#var,'Record 3')
-- Example 2
INSERT INTO #temp VALUES (1,2)
INSERT INTO #temp VALUES (1,2)
INSERT INTO ActualTable (col1, col2, sequence)
SELECT temp.*, (SELECT MAX(ID) + 1 FROM ActualTable)
FROM #temp temp
-- Example 3
DECLARE #var int
INSERT INTO ActualTable (col1, col2, sequence) OUTPUT #var = inserted.sequence VALUES (1, 2, (SELECT MAX(ID) + 1 FROM ActualTable))
The first two examples rely on batch updating. But based on your comment, I have added example 3 which is a single input initially. You can then use the sequence that was inserted to insert the rest of the records. If you have never used an output, please reply in comments and I will expand further.
I would isolate all of the above inside of a transactions.
If you were using SQL Server 2012, you could use the SEQUENCE operator as shown here.
Forgive me if syntax errors, don't have SSMS installed
I have two databases.I insert data from DATABASE_2 TO DATABASE_1 however i need to convert some column.
I must convert Customer_Telephone_Number from varchar to bigint after that insert it.
So,
My Question is in below.
SET IDENTITY_INSERT DATABASE_1.dbo.CUSTOMER_TABLE ON
INSERT INTO DATABASE_1.dbo.CUSTOMER_TABLE
(
Customer_Id,
Customer_Telephone_Number
)
Select
Customer_Id,
Customer_Telephone_Number // This is varchar so i need to convert it to Big int.
from
DATABASE_2.DBO.CUSTOMER_TABLE
Any help will be appreciated.
Thanks.
If the data stored is without spaces or other non numeric symbols:
Select
Customer_Id,
CONVERT(BIGINT,Customer_Telephone_Number)
from
DATABASE_2.DBO.CUSTOMER_TABLE
For instance, if there is value with (222)-3333-333 it would fail. If the value was 2223333333 it would succeed
I am trying to write a Stored Procedure in SQL Server (2005) to do something that sounds simple, but is actually proving to be more difficult that I thought.
I have a table with 30 columns and 50,000 rows.
The number of records is fixed, but users can edit the fields of existing records.
To save them having to re-key repetitive data, I want to give them the ability to select a record, and specify a range of IDs to copy those details to.
The SP I'm trying to write will take 3 parameters: The source record primary key, and the lower and upper primary keys of the range of records that the data will be copied into.
Obviously the PKs of the destination records remain unchanged.
So I figured the SP needs to do a SELECT - to get all the data to be copied, and an UPDATE - to write the data into the specified destination records.
I just don't know how to store the results of the SELECT to slot them into the UPDATE.
A temp table wouldn't help - selecting from that would be just the same as selecting from the table!
What I need is a variable that is effectively a single record, so I can go something like:
#tempRECORD = SELECT * FROM SOURCETABLE WHERE ID = #sourcePK
UPDATE SOURCETABLE
SET FIELD1 = #tempRECORD.FIELD1,
FIELD2 = #tempRECORD.FIELD2,
...
FIELD30 = #tempRECORD.FIELD30
WHERE ID >= #LOWER_id AND ID <= #UPPER_id
But I don't know how, or if you even can.
I'm also open to any other clever way I haven't even thought of!
Thanks guys!
So I figured the SP needs to do a SELECT - to get all the data to be copied, and an UPDATE - to write the data into the specified destination records.
What you need is the T-SQL-specific extension to UPDATE, UPDATE ... FROM:
UPDATE T
SET
Field1 = source.Field1
, Field2 = source.Field2
, Field3 = source.Field3
FROM
(SELECT * FROM T AS source_T WHERE source_T.ID = #sourcePK) as source
WHERE
T.ID BETWEEN #LOWER_Id AND #UPPER_Id
Note that this ability to put a FROM clause in an UPDATE statement is not standard ANSI SQL, so I don't know how this would be done in other RDBMSs.
I am pretty sure this ain't the easiest way to do it, but it should work without any problems:
DECLARE #tempField1 varchar(255)
DECLARE #tempField2 varchar(255)
...
DECLARE #tempField30 varchar(255)
SELECT #tempField1 = FIELD1, #tempField2 = FIELD2, ... ,#tempField30 = FIELD30 FROM SOURCETABLE WHERE ID = #sourcePK
UPDATE SOURCETABLE
SET FIELD1 = #tempField1,
FIELD2 = #tempField2,
...
FIELD30 = #tempField30
WHERE ID >= #LOWER_id AND ID <= #UPPER_id
You would need to edit the tempField variables so that they have the right type.