I have this question regarding computed columns. This is the first time that I work with them, and I do not understand why I'm getting an error.
Let's assume I have a table already created:
create table testComputed
(
a int null,
b int null
)
Now, I want to update it with another couple of columns including a computed one:
alter table testcomputed add c int null;
alter table testcomputed add d int null;
alter table testcomputed add e as c + d;
However, I'm getting this error message:
Msg 207, Level 16, State 1, Line 10
Invalid column name 'c'
Msg 207, Level 16, State 1, Line 10
Invalid column name 'd'
What is missing in the code, why the computed column is not created?
As I mention in the comment, the problem here is that the parsing/compilation is failing. Prior to the batch actually running it is parsed, and only some objects/properties benefit from the parser knowing that the object was created previous in the batch, and thus not failing; columns are not one of these. As such when the batch is parsed, the columns c and d do not exist at that point, and so the the parser generates an error.
The simple solution would be to separate the latter statement into a separate batch. In an application like SSMS that would just mean adding a batch separator (traditionally GO):
ALTER TABLE dbo.testcomputed ADD c int NULL;
ALTER TABLE dbo.testcomputed ADD d int NULL;
GO
ALTER TABLE dbo.testcomputed ADD e AS c + d;
GO
If you need to do it in the same batch, you could defer the parsing by using sys.sp_executsql:
ALTER TABLE dbo.testcomputed ADD c int NULL;
ALTER TABLE dbo.testcomputed ADD d int NULL;
EXEC sys.sp_executesql N'ALTER TABLE dbo.testcomputed ADD e AS c + d;';
Related
I am looking to retrieve a value of the profit (FilmBoxOfficeDollar - FilmBudgetDollars) based on the Studio given as a parameter to the function.
USE Movies;
GO
CREATE FUNCTION fnmovieProfits(#StudioName nvarchar(255))
RETURNS int
AS
BEGIN
RETURN (SELECT SUM(FilmBoxOfficeDollars - FilmBudgetDollars)
FROM Film JOIN Studio
ON Film.FilmStudioID = Studio.StudioID
WHERE StudioName = #StudioName);
END;
GO
SELECT [dbo].[fnmovieProfits]('Dreamworks');
Whenever I run this through to pull the piece of data I get the following error:
Msg 8115, Level 16, State 2, Line 13
Arithmetic overflow error converting expression to data type int.
Any help would be much appreciated!
The problem you are experiencing is that you are overflowing the allowed value of a 32 bit number (INT); if you cast/convert to a 64 bit number (BIGINT) and return that datatype, the issue will be corrected. Proof of concept showing the issue:
DECLARE #BigNumber INT=2000000000
select CONVERT(BIGINT,#BigNumber) + CONVERT(BIGINT,#BigNumber) --returns 4,000,000,000
select (#BigNumber + #BigNumber) --errors with "Arithmetic overflow error converting expression to data type int."
BUT, do yourself a favor and use a view instead. Scalars like that are terrible for performance in reports. Scalar functions should never be used unless they are simply doing calculations based on input values (i.e. not hitting underlying, persisted data).
CREATE VIEW dbo.v_StudioProfits
AS
SELECT
StudioName,
SUM(CONVERT(BIGINT,FilmBoxOfficeDollars) - CONVERT(BIGINT,FilmBudgetDollars)) AS [Profit]
FROM Film
INNER JOIN Studio ON Film.FilmStudioID = Studio.StudioID
GROUP BY StudioName
GO
SELECT * FROM dbo.v_StudioProfits WHERE StudioName='Dreamworks'
Relevant reading on SQL Server datatypes. Specifically, integer datatypes.
Your sum is exceeding int range. You should define your return type as bigint:
CREATE FUNCTION fnmovieProfits(#StudioName nvarchar(255))
RETURNS bigint
AS.......
The maximum value you can return with int as a return type is 2147483647. Your sum is probably bigger than that.
One example of function that exceeds its return type:
CREATE FUNCTION testFunction()
RETURNS int
AS
BEGIN
RETURN (SELECT 2147483647 + 1);
END;
GO
SELECT [dbo].[testFunction]();
If you execute it you will get the following error:
Msg 8115, Level 16, State 2, Line 8
Arithmetic overflow error converting expression to data type int.
So the solution is just to increase your return type range by replacing int with bigint.
I'm trying to add one more value to my varray list of numbers called burse using multiset union all but I get this error. [1
But when I insert a single value its working. Example:
What I am doing wrong ?
This is how I declare and insert into column
This should work...
update student
set istoric = istoric multiset union all bure(42, 23)
where id = 1
... except that you're now using a VARRAY (and not the nested table you had in your previous question). So you get an error message:
ORA-00932: inconsistent datatypes: expected UDT got BURE
The reason is, according to the documentation:
"While nested tables can also be changed in a piecewise fashions, varrays cannot....However, you cannot update or delete individual varray elements directly with SQL; you have to select the varray from the table, change it in PL/SQL, then update the table to include the new varray." (emphasis mine)
This is because VARRAYs are ordered sets while Nested Tables are not. Unless there is a firm requirement to maintain the order of elements it is better to use Nested Tables rather than Varrays: they're just more convenient.
So here is how you can update a Varray using PL/SQL:
declare
lv bure;
cnt pls_integer;
begin
select istoric into lv
from student
where id = 1;
cnt := lv.count();
lv.extend();
lv(cnt+1) := 23 ;
lv.extend();
lv(cnt+2) := 69 ;
update student
set istoric = lv
where id = 1;
end;
/
I am new to T-SQL. What is the meaning of the following statement?
BEGIN
UPDATE table_name
SET a = ISNULL(#f_flag,0)
END
Begin, End: The Begin and End is not needed. It identifies a code
block, usefull if more that one statement.
UPDATE table_name: Update the data in the table "table_name".
SET: Keyword, start the comma delimited list of column - value pairs
to update
a = : a is the column mame, to value to the right of the = is what
value will be used
ISNULL(#f_flag,0): The value to assign. In this case the IsNull checks the value of the #f_flag variable, and if it is null, then use a 0.
*Note: that there is no "WHERE" clause here, therefore, all rows in the table will be updated.
How to set 5 variables from a result of function in SQL Server, without creating other table
If there is a function that returns a table and I'm setting a var to a result where a condition satisfies aka. (#counter), how would I procede if I want to get 5 values from the temp table is created??
SELECT #var1 = items
FROM dbo.FUNCTION()
WHERE itemindex = #counter
SELECT #var1,#var2,#var3,#var4,#var5 = items FROM ... but I know this can not be done, any idea??
You cannot do this - a stored function can either return:
one single scalar value
a table of data
If you convert this to a stored procedure, you could define five output parameters for your call - that might work
CREATE PROCEDURE dbo.YourProc #InParam1 INT,
#OutParam1 INT OUTPUT,
#OutParam2 INT OUTPUT,
#OutParam3 INT OUTPUT,
#OutParam4 INT OUTPUT,
#OutParam5 INT OUTPUT
AS BEGIN
....
END
I need to execute a query that is highly dependent on several conditions what need to be checked by analyzing that data in other tables, the base goal is to return the rows from the tables if all of the conditions in the other tables are true, I am fed up with INNER joins LEFT joins and WHERE statement, i need to look up one table, if the returned value is 1, 0 or 4 or a set of values, i need to execute an other statement, and based on the resuts of that i need to execute one last statement which is my final result.
as far as functions are procedures are concerned, i studies the MySQL documentation like hell and all it gives me is this ::
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `SimpleCompare`(n INT, m INT) RETURNS varchar(20) CHARSET latin1
BEGIN
DECLARE s VARCHAR(20);
IF n > m THEN SET s = '>';
ELSEIF n = m THEN SET s = '=';
ELSE SET s = '<';
END IF;
SET s = CONCAT(n, ' ', s, ' ', m);
RETURN s;
END
Now this is so plain, i dont even know where to start, I the "returns varchar(20)" what does it need to be if im expecting it to return a table of 10 rows and not a VARCHAR(20), what do I declare "DECLARE s VARCHAR(20);" as if i want it to be a table not a VARCHAR(20).
the (n > m) after the "IF" how to i replace it with my own query ,
and after I do that, the "THEN SET s = '>'" how do i set s = to the query results ?, this is driving me crazy the syntax is beyond me, and the documentation does not explain anything.
Thanks in advance
To my knowledge, MySQL doesn't support a table valued data type. The use of the function you posted would be:
SELECT simplecompare(yt.n, yt.m) AS eval
FROM YOUR_TABE yt
...which would return:
eval
--------
1 = 1
2 < 3
etc.
SQL is set based, which is different from typical programming (procedural or OO).