I would like to create a calculated field within one of my tables within the database. I am using visual basic and my IDE is visual studio.
I recently created the same database using access and used the following calculation within a calculated field’s expression:
(([Grade1]/10)*2)+(([Grade2]/10)*3)+(([Grade3]/10)*5)
As a first go I just pasted to code into the default value or binding of the field as a long shot, but got an error. Guess I’m not allowed to make calculations using data from existing columns.
Can anyone help me with creating this field? The field does not need to be within the database it would be preferred however if it could be calculated outside of the database on a form using datagridview or something like that would be fine.
Grade 1, 2 and 3 contain's a number from 0 to 100.
I can’t find any tutorials unless anyone can point me in the right direction?
In order to get the calculated field as described you should use the following T-SQL code:
create table dbo.Enrolement
(
StudentID int not null,
ModuleNUmber int not null,
Grade1 nchar(3) not null,
Grade2 nchar(3) not null,
Grade3 nchar(3) not null,
Overall as cast(((Grade1 / 10 * 2) + (Grade2 / 10 * 3) + (Grade3 / 10 * 5)) as nchar(10))
)
Yet, I do not understand why you are storing the grades as text. More over, your T-SQL code requires an implicit conversions of the text to numbers, make the calculation, and then revert it back to text again. Furthermore, during the conversion you are not telling SQL what do convert to. So, if you have grades with decimal places then a SELECT from the table will fail.
insert into dbo.Enrolement
(
StudentID,
ModuleNUmber,
Grade1,
Grade2,
Grade3
)
values (
2, -- StudentID - int
101, -- ModuleNUmber - int
N'1.2', -- Grade1 - nchar(3)
N'1.8', -- Grade2 - nchar(3)
N'3.9' -- Grade3 - nchar(3)
)
select *
from dbo.Enrolement
Msg 245, Level 16, State 1, Line 17 Conversion failed when converting
the nvarchar value '1.2' to data type int.
So, I'd very much recommend you using numbers to store your grades if they are to be used in a calculation afterwards. Here is the same table with numbers instead:
create table dbo.Enrolement
(
StudentID int not null,
ModuleNUmber int not null,
Grade1 decimal(9, 3) not null,
Grade2 decimal(9, 3) not null,
Grade3 decimal(9, 3) not null,
Overall as ((Grade1 / 10 * 2) + (Grade2 / 10 * 3) + (Grade3 / 10 * 5))
)
I have chosen to use decimal(9,3) because any precision from 1 to 9 uses the same amount of storage in bytes. At the same time I limited the decimal places to three and thus allow for rounding on two decimal places. At the same time there is ample of room to potentially "add" grades (if this should ever make sense) to a grand total of 999999.999
Related
I have a two fields that identify a user, one being a Integer and one being a varchar(10) in the format of 'AA111X' where the first two are alpha and the final x is alphanumeric, and need to convert that into an integer for the integer field as a translation. The integer value used to be provided for us but is no longer. The answer may well be this isn't possible, and a lookup table will have to be used but I'm trying to avoid the schema change if possible.
Is it necessary that you actually treat the first two characters as some value base 26, and the last character as some value base 36? Or is it only necessary that you can generate a unique integer for any possible input, in a way that can be converted back if necessary?
If the latter, and if the existing values are considered case insensitive, this solution will always result in a value that fits in a 4 byte integer:
declare #val varchar(10) = 'zz111z';
select cast(
concat(
ascii(substring(val, 1, 1)),
ascii(substring(val, 2, 1)),
substring(val, 3, 3),
ascii(substring(val, 6, 1))
)
as int
)
from (select upper(#val)) v(val);
A table of financials has been provided to me with the following datatypes:
billed varchar 9
allowed varchar 9
paid varchar 7
with the following columns and values:
billed = 2555 allowed = 1051 paid = 951
I want to convert the varchar values (the whole column) to money or to some format where I'll have a $ sign and the number will have 2 decimal points instead of rounding up. I need the SUM to remain because I'm adding up values throughout the columns based on the date.
My Expected Results are:
BILLED
$2,554.67
ALLOWED
$1,050.75
PAID
$950.75
I have code that I've used, but I can't seem to format it correctly to be viewable in the post.`
Cast the values as numeric, do math with a function like sum, format as money and concatenate the $ symbol at the beginning.
Simplified example doing conversion:
select ('$' + FORMAT(CONVERT(MONEY, cast([allowed] as numeric(38,2))), '###,###.####')) as AllowedConversionExample
from dbo.payments
Simplified example with math using sum()
select
'$' + FORMAT(CONVERT(MONEY, sum(cast(V.Val as numeric(38,2)))), '###,###.####')
from (
select cast('1050.75' as varchar(9)) Val
union select cast('950.75' as varchar(9))
) V
In my table I've got column facebook where I store facebook data ( comment count, share count etc.) and It's an array. For example:
{{total_count,14},{comment_count,0},{comment_plugin_count,0},{share_count,12},{reaction_count,2}}
Now I'm trying to SELECT rows that facebook total_count is between 5 and 10. I've tried this:
SELECT * FROM pl where regexp_matches(array_to_string(facebook, ' '), '(\d+).*')::numeric[] BETWEEN 5 and 10;
But I'm getting an error:
ERROR: operator does not exist: numeric[] >= integer
Any ideas?
There is no need to convert the array to text and use regexp. You can access a particular element of the array, e.g.:
with pl(facebook) as (
values ('{{total_count,14},{comment_count,0},{comment_plugin_count,0},{share_count,12},{reaction_count,2}}'::text[])
)
select facebook[1][2] as total_count
from pl;
total_count
-------------
14
(1 row)
Your query may look like this:
select *
from pl
where facebook[1][2]::numeric between 5 and 10
Update. You could avoid the troubles described in the comments if you would use the word null instead of empty strings ''''.
with pl(id, facebook) as (
values
(1, '{{total_count,14},{comment_count,0}}'::text[]),
(2, '{{total_count,null},{comment_count,null}}'::text[]),
(3, '{{total_count,7},{comment_count,10}}'::text[])
)
select *
from pl
where facebook[1][2]::numeric between 5 and 10
id | facebook
----+--------------------------------------
3 | {{total_count,7},{comment_count,10}}
(1 row)
However, it would be unfair to leave your problems without an additional comment. The case is suitable as an example for the lecture How not to use arrays in Postgres. You have at least a few better options. The most performant and natural is to simply use regular integer columns:
create table pl (
...
facebook_total_count integer,
facebook_comment_count integer,
...
);
If for some reason you need to separate this data from others in the table, create a new secondary table with a foreign key to the main table.
If for some mysterious reason you have to store the data in a single column, use the jsonb type, example:
with pl(id, facebook) as (
values
(1, '{"total_count": 14, "comment_count": 0}'::jsonb),
(2, '{"total_count": null, "comment_count": null}'::jsonb),
(3, '{"total_count": 7, "comment_count": 10}'::jsonb)
)
select *
from pl
where (facebook->>'total_count')::integer between 5 and 10
hstore can be an alternative to jsonb.
All these ways are much easier to maintain and much more efficient than your current model. Time to move to the bright side of power.
Is there any way to combine data types in SQL Server? i.e. have the value of a cell to be both text and number where the text is always the same?
I have a table called Contract. The ContractID field should have the value of: 'TCwxyz' where 'TC' are string characters and 'wxyz' are integers.
I have the following but it doesn't seem to be working:
CREATE TYPE TenantContracts AS CHAR(6)
CHECK (SUBSTRING(VALUE,1,2)='TC'
AND (SUBSTRING(VALUE,2,4) AS SMALLINT)
Any assistance would be appreciated.
Constraints are added to the table definition, you don't need to create a type.
ALTER TABLE Contract
ADD CONSTRAINT chk_ContractID CHECK (
SUBSTRING(ContractID, 1, 2) = 'TC'
AND ISNUMERIC(SUBSTRING(ContractID, 3, 4)) = 1
)
This solution will accept a few incorrect values, for instance TC1.01. I'd just use this for the virtue of simplicity though, rather than trying to determine if the last 4 digits are an integer, which gets surprisingly tricky (T-sql - determine if value is integer).
Edit: If you did want to make a more robust integer check, perhaps best would be to simply check individually if each of the last 4 characters is numeric:
ALTER TABLE Contract
ADD CONSTRAINT chk_ContractID CHECK (
SUBSTRING(ContractID, 1, 2) = 'TC'
AND ISNUMERIC(SUBSTRING(ContractID, 3, 1)) = 1
AND ISNUMERIC(SUBSTRING(ContractID, 4, 1)) = 1
AND ISNUMERIC(SUBSTRING(ContractID, 5, 1)) = 1
AND ISNUMERIC(SUBSTRING(ContractID, 6, 1)) = 1
)
I have to count the digits after the decimal point in a database hosted by a MS Sql Server (2005 or 2008 does not matter), in order to correct some errors made by users.
I have the same problem on an Oracle database, but there things are less complicated.
Bottom line is on Oracle the select is:
select length( substr(to_char(MY_FIELD), instr(to_char(MY_FILED),'.',1,1)+1, length(to_char(MY_FILED)))) as digits_length
from MY_TABLE
where the filed My_filed is float(38).
On Ms Sql server I try to use:
select LEN(SUBSTRING(CAST(MY_FIELD AS VARCHAR), CHARINDEX('.',CAST(MY_FILED AS VARCHAR),1)+1, LEN(CAST(MY_FIELD AS VARCHAR)))) as digits_length
from MY_TABLE
The problem is that on MS Sql Server, when i cast MY_FIELD as varchar the float number is truncated by only 2 decimals and the count of the digits is wrong.
Can someone give me any hints?
Best regards.
SELECT
LEN(CAST(REVERSE(SUBSTRING(STR(MY_FIELD, 13, 11), CHARINDEX('.', STR(MY_FIELD, 13, 11)) + 1, 20)) AS decimal))
from TABLE
I have received from my friend a very simple solution which is just great. So I will post the workaround in order to help others in the same position as me.
First, make function:
create FUNCTION dbo.countDigits(#A float) RETURNS tinyint AS
BEGIN
declare #R tinyint
IF #A IS NULL
RETURN NULL
set #R = 0
while #A - str(#A, 18 + #R, #r) <> 0
begin
SET #R = #R + 1
end
RETURN #R
END
GO
Second:
select MY_FIELD,
dbo.countDigits(MY_FIELD)
from MY_TABLE
Using the function will get you the exact number of digits after the decimal point.
The first thing is to switch to using CONVERT rather than CAST. The difference is, with CONVERT, you can specify a format code. CAST uses whatever the default format code is:
When expression is float or real, style can be one of the values shown in the following table. Other values are processed as 0.
None of the formats are particularly appealing, but I think the best for you to use would be 2. So it would be:
CONVERT(varchar(25),MY_FIELD,2)
This will, unfortunately, give you the value in scientific notation and always with 16 digits e.g. 1.234567890123456e+000. To get the number of "real" digits, you need to split this number apart, work out the number of digits in the decimal portion, and offset it by the number provided in the exponent.
And, of course, insert usual caveats/warnings about trying to talk about digits when dealing with a number which has a defined binary representation. The number of "digits" of a particular float may vary depending on how it was calculated.
I'm not sure about speed. etc or the elegance of this code. it was for some ad-hoc testing to find the first decimal value . but this code could be changed to loop through all the decimals and find the last time a value was greater than zero easily.
DECLARE #NoOfDecimals int = 0
Declare #ROUNDINGPRECISION numeric(32,16) = -.00001000
select #ROUNDINGPRECISION = ABS(#ROUNDINGPRECISION)
select #ROUNDINGPRECISION = #ROUNDINGPRECISION - floor(#ROUNDINGPRECISION)
while #ROUNDINGPRECISION < 1
Begin
select #NoOfDecimals = #NoOfDecimals +1
select #ROUNDINGPRECISION = #ROUNDINGPRECISION * 10
end;
select #NoOfDecimals