We have a legacy interface that inserts into table T1 that values "BODY_TEXT" (varcharmax), "BODY_BIN"(varbinarymax).
It currently inserts just to one of the columns, and leave the other one NULL.
Now we implemented a new interface - table T2 that has only "BODY"(varbinarymax) column.
I need to create a view V1 that should replace T1, meaning
CREATE VIEW V1 AS
SELECT
T2.UNIQUE_ID AS UNIQUE_ID,
etc…
Now I don't know how to treat T2.BODY column… I need to do something like
T2.BODY AS (whatever is not null(BODY_BIN, BODY_TEXT)). It must also support varcharmax vs. varbinarymax.
I tried implementing COALESCE meaning T2.BODY AS COALESCE(BODY_BIN, BODY_TEXT) but it doesn't work.
Nor does
COALESCE(BODY_BIN, BODY_TEXT) AS BODY
T2.BODY AS BODY
Again - In the legacy table we had T1 with two columns - BODY_BIN and BODY_TEXT. The user inserted one value and left the other one null, since body is either binary or textual but not both. The new interface has a table T2 that has only one column, BODY (varbinarymax), and I was asked to delete table T1 and create a view with the same name. Meaning in order to preserve backward comparability they should still be able to perform "insert into T1 values X,Y" (X is DATA_BIN or NULL, and Y is DATA_TEXT or NULL), but the content (taken from either X or Y) should be translated into ONE column in the T2 table - BODY.
I have no idea how to pull this one up.
Can you help me?
Thanks,
Nili
varbinary to varchar (note the order) will cast implicitly. So this works because ISNULL takes the first datatype
ISNULL(varchar, varbinary)
COALESCE fails because it takes the highest precedence datatype (which is varbinary). The implicit cast is not allowed. ISNULL(varbinary, varchar) would fail too
You need an explicit CAST
DECLARE #foo TABLE (ID int IDENTITY (1,1), charmax varchar(MAX) NULL, binmax varbinary(MAX) NULL)
INSERT #foo (charmax, binmax) VALUES ('text', NULL)
INSERT #foo (charmax, binmax) VALUES (NULL, 0x303131)
INSERT #foo (charmax, binmax) VALUES ('Moretext', NULL)
INSERT #foo (charmax, binmax) VALUES (NULL, 0x414243454647)
SELECT ISNULL(binmax, CONVERT(varbinary(MAX), charmax))
FROM #foo
or
SELECT COALESCE(binmax, CONVERT(varbinary(MAX), charmax))
FROM #foo
Edit: I understand the question now... maybe
DECLARE #foo2 TABLE (ID int IDENTITY (1,1), BODY varbinary(MAX) NULL)
INSERT #foo2 (BODY) VALUES (CAST('text' AS varbinary(MAX)))
INSERT #foo2 (BODY) VALUES (0x303132)
INSERT #foo2 (BODY) VALUES (CAST('Moretext' AS varbinary(MAX)))
INSERT #foo2 (BODY) VALUES (0x414243454647)
SELECT
BODY AS BODY_BIN,
CAST(BODY AS varchar(MAX)) AS BOY_TEXT
FROM
#foo2
Edit2: something like this (not tested) to maintain the same write interface. Normally, I'd only maintain a read interface hence the confusion...
CREATE VIEW OldFoo
AS
SELECT
ID,
BODY AS BODY_BIN,
CAST(BODY AS varchar(MAX)) AS BOY_TEXT
FROM
newFoo
GO
CREATE TRIGGER ON OldFoo INSTEAD OF INSERT
AS
SET NOCOUNT ON
INSERT newFoo (BODY)
SELECT ISNULL(binmax, CONVERT(varbinary(MAX), charmax))
FROM INSERTED
GO
First, this is a bad design. Joining on a varchar(max) or varbinary(max) field is a bad idea since they can't be indexed. Prepare for table scans!
You have inconsistent data types in the same column, which is a problem.
Try:
CAST((COALESCE(BODY_BIN, BODY_TEXT)) as varchar(max))
Related
Can I do something like this, column is of type nchar(8), but the string I wanted to store in the table is longer than that.
The reason I am doing this is because I want to convert from one table to another table. Table A is nchar(8) and Table B is nvarchar(100). I want all characters in Table B transfer to Table A without missing any single character.
If the nvarchar(100) contains only latin characters with a length up to 16 chars, then you can squeeze the nvarchar(100) into the nchar(8):
declare #t table
(
col100 nvarchar(100),
col8 nchar(8)
);
insert into #t(col100) values('1234567890123456');
update #t
set col8 = cast(cast(col100 as varchar(100)) as varbinary(100))
select *, cast(cast(cast(col8 as varbinary(100)) as varchar(100)) as nvarchar(100)) as from8to100_16charsmax
from #t;
If you cannot modify A, then you cannot use it to store the data. Create another table for the overflow . . . something like:
create table a_overflow (
a_pk int primary key references a(pk),
column nvarchar(max) -- why stop at 100?
);
Then, you can construct a view to bring in the data from this table when viewing a:
create view vw_a as
select . . . , -- all the other columns
coalesce(ao.column, a.column) as column
from a left join
a_overflow ao
on ao.a_pk = a.pk;
And, if you really want to "hide" the view, you can create an insert trigger on vw_a, which inserts the appropriate values into the two tables.
This is a lot of work. Simply modifying the table is much simpler. That said, this approach is sometimes needed when you need to modify a large table and altering a column would incur too much locking overhead.
I got the error where my data type is varchar, then I want to insert value/input in textboxt = 'smh85670s'.
It appear to be error. As far as I know varchar can accept characters and numbers, but why does it keep throwing this error?
If I insert value '123456' the table can accept that value.
Please guide me. What data type should I use?
Assuming that you are using Stored procedures (which have an insert query) or directly firing an insert query into DB, you must be sending all data as parameters like say #param1, #param2,...
Your insert query will be like
INSERT INTO Sometable ( Amount, textbox,... )
SELECT #param1, #param2 ,...
Just add a cast in this query to make it work
INSERT INTO Sometable ( Amount, textbox,... )
SELECT #param1, CAST(#param2 as varchar),...
I have a bigint PK column which is NOT an identity column, because I create the number in a function using different numbers. Anyway, I am trying to save this bigint number in a parameter #InvID, then use this parameter later in the procedure.
ScopeIdentity() is not working for me, it saved Null to #InvID, I think because the column is not an identity column. Is there anyway to select the record that was just inserted by the procedure without adding an extra ID column to the table?
It would save me a lot of effort and work if there is a direct way to select this record and not adding an id column.
insert into Lab_Invoice(iID, iDate, iTotal, iIsPaid, iSource, iCreator, iShiftID, iBalanceAfter, iFileNo, iType)
values (dbo.Get_RI_ID('True'), GETDATE(),
(select FilePrice from LabSettings), 'False', #source, #user, #shiftID, #b, #fid, 'Open File Invoice');
set #invID = CAST(scope_identity() AS bigint);
P.S. dbo.Get_RI_ID('True') a function returns a bigint.
Why don't you use?
set #invId=dbo.Get_RI_ID('True');
insert into Lab_Invoice(iID,iDate,iTotal,iIsPaid,iSource,iCreator,iShiftID,iBalanceAfter,iFileNo,iType)
values(#invId,GETDATE(),(select FilePrice from LabSettings),'False',#source,#user,#shiftID,#b,#fid,'Open File Invoice');
You already know that big id value. Get it before your insert statement then use it later.
one way to get inserted statement value..it is not clear which value you are trying to get,so created some example with dummy data
create table #test
(
id int
)
declare #id table
(
id int
)
insert into #test
output inserted.id into #id
select 1
select #invID=id from #id
I got some serial keys to find in sql database, such as “A-B-C”,”D-E-F”,”G-H-I”,”J-K-L” and they are stored in tblTemp using ntext data type. These above keys may store in three columns, colA, colB and colC (sometimes store in one column and the rest are null). Sometimes, two serial keys can find in one column (e.g. A-B-C;D-E-F) using “;” seperated. so i wrote the following sql query.
Declare #sa TABLE(var1 nvarchar(Max));
Insert INTO #sa(var1) VALUES (N’A-B-C’);
Insert INTO #sa(var1) VALUES (N’D-E-F’);
Insert INTO #sa(var1) VALUES (N’G-H-I’);
Insert INTO #sa(var1) VALUES (N’J-K-I’);
SELECT * FROM tblTemp
WHERE colA IN (SELECT var1 FROM #sa);
so i got the following error message.
The data types ntext and nvarchar(max) are incompatible in the equal to operator.
I still need to find for colB and colC. How should write query for this kind of situation?
all suggestions are welcome.
CAST/CONVERT (msdn.microsoft.com) your var1 to NTEXT type in your query so that the types are compatible.
SELECT
*
FROM
tblTemp
WHERE
colA IN (
SELECT
CAST(var1 AS NTEXT)
FROM
#sa
);
You have to convert/cast your search term as an appropriate data type, in this case text.
Try this:
Declare #sa TABLE(var1 nvarchar(Max));
Insert INTO #sa(var1) VALUES (N’A-B-C’);
Insert INTO #sa(var1) VALUES (N’D-E-F’);
Insert INTO #sa(var1) VALUES (N’G-H-I’);
Insert INTO #sa(var1) VALUES (N’J-K-I’);
SELECT *
FROM tblTemp t
WHERE EXISTS (SELECT 1
FROM #sa s
WHERE t.colA like cast('%'+s.var1+'%' as text)
OR t.colB like cast('%'+s.var1+'%' as text)
OR t.colC like cast('%'+s.var1+'%' as text)
);
Since all suggestions are welcome.
How about change the datatype on tblTemp to NVARCHAR(MAX)?
NTEXT was deprecated with the introduction of NVARCHAR(MAX) in 2005.
ALTER TABLE tblTemp ALTER COLUMN colA NVARCHAR(MAX)
I'm inserting into an SQLServer table with an autoincrementing key field. (I believe this is called an IDENTITY column in SQLServer.)
In Oracle, I can use the RETURNING keyword to give my INSERT statement a results set like a SELECT query that will return the generated value:
INSERT INTO table
(foreign_key1, value)
VALUES
(9, 'text')
RETURNING key_field INTO :var;
How do I accomplish this in SQLServer?
Bonus: Okay, nice answers so far, but how do I put it into a single statement, if possible? :)
In general, it can't be done in a single statement.
But the SELECT SCOPE_IDENTITY() can (and should) be placed directly after the INSERT statement, so it's all done in the same database call.
Example:
mydb.ExecuteSql("INSERT INTO table(foreign_key1, value) VALUES(9, 'text'); SELECT SCOPE_IDENTITY();");
You can use OUTPUT, but it has some limitations you should be aware of:
http://msdn.microsoft.com/en-us/library/ms177564.aspx
SELECT SCOPE_IDENTITY()
Edit: Having a play...
If only the OUTPUT clause supported local variables.
Anyway, to get a range of IDs rather than a singleton
DECLARE #Mytable TABLE (keycol int IDENTITY (1, 1), valuecol varchar(50))
INSERT #Mytable (valuecol)
OUTPUT Inserted.keycol
SELECT 'harry'
UNION ALL
SELECT 'dick'
UNION ALL
SELECT 'tom'
Edit 2: In one call. I've never had occasion to use this construct.
DECLARE #Mytable TABLE (keycol int IDENTITY (1, 1), valuecol varchar(50))
INSERT #Mytable (valuecol)
OUTPUT Inserted.keycol
VALUES('foobar')
In addition to ##IDENTITY, you should also look into SCOPE_IDENTITY() and IDENT_CURRENT(). You most likely want SCOPE_IDENTITY(). ##IDENTITY has a problem in that it might return an identity value created in a trigger on the actual table that you're trying to track.
Also, these are single-value functions. I don't know how the Oracle RETURNING keyword works.
SCOPE_IDENTITY
It depends on your calling context.
If you're calling this from client code, you can use OUTPUT and then read the value returned.
DECLARE #t TABLE (ColID int IDENTITY, ColStr varchar(20))
INSERT INTO #t (ColStr)
OUTPUT Inserted.ColID
VALUES ('Hello World')
Result:
ColID
-----------
1
If you're wrapping this in a stored procedure, using OUTPUT is more work. There, you'll want to use SCOPE_IDENTITY(), but you can't do it in a single statement. Sure, you can put multiple statements on a single line with a ';' separator, but that's not a single statement.
DECLARE #idValue int
DECLARE #t TABLE (ColID int IDENTITY, ColStr varchar(20))
INSERT INTO #t (ColStr) VALUES ('Hello World')
SELECT #idValue = SCOPE_IDENTITY()
Result: #idValue variable contains identity value. Use an OUTPUT parameter to return the value.
You can use OUTPUT INTO, which has the additional benefits of being able to capture multiple identities inserted.
INSERT INTO table(foreign_key1, value)VALUES(9, 'text');SELECT ##IDENTITY;