I want to add to a table in my DB ("InjuryScenario") a dynamic id (because i work with visual studio c#) and i tried this:
declare #InjuryScenarioTMPp int;
set #InjuryScenarioTMPp = (select MAX (InjuryScenario_id) from InjuryScenario) +1;
print #InjuryScenarioTMPp;
when i printed it, it doesn't show me anything.
when i tried to add a row to the table and i tried the 3 rows (up) again it does print "2".
maybe when i don't have any rows in the table it doesn't know how to do (NULL+1)?
does anyone have an idea why?
It depends on what kind of database would you like to use. For example, in MySQL you have to use AUTO INCREMENT on one field. But in Postgres or in Oracle, you should create first a sequence and later than add the next value of this sequence to new record.
A NULLvalue is an unknown value, and the result of arithmetic on unknown values is also unknown. What you can do is to use either theCOALESCEor theISNULLfunction to replace the NULLvalue with 0when you use it:
declare #InjuryScenarioTMPp int;
set #InjuryScenarioTMPp = (select ISNULL(MAX(InjuryScenario_id),0) from InjuryScenario) + 1;
print #InjuryScenarioTMPp;
See MSDN: COALESCE and ISNULL
For an example:
declare #i int
set #i = null
select #i+1, coalesce(#i, 0)+1, isnull(#i, 0)+1
set #i = 1
select #i+1, coalesce(#i, 0)+1, isnull(#i, 0)+1
Output:
----------- ----------- -----------
NULL 1 1
(1 row(s) affected)
----------- ----------- -----------
2 2 2
(1 row(s) affected)
Related
I have three tables and there respective columns
tReferences:
PK_Reference
FK_ReferenceType
ReferenceValue
thePKofMain_FK
tReferencesTypes:
PK_ReferenceType
ReferenceName
tMain:
PK_Main
FirstReferenceValue
SecondReferenceValue
ThirdReferenceValue
Three references have become important enough that they are going to have to go to the tMain table. Let's say the PK of the three references from tReferenceTypes are 321, 654, and 987. I need to copy the references values from tReference to tMain table where each reference has their own columns now, but I have to make sure that I am adding the value from tReference to the correct PK_Main which is suppose to be the same value as the thePKofMain_FK in tReference table, and that I amtReferenceType PK.
I need something like this...
UPDATE tMain
SET
tMain.FirstReferenceValue = (SELECT ReferenceValue FROM tReference WHERE FK_referenceType =321)
FROM tReference
WHERE tReference. thePKofMain_FK = tMain.PK_Main
But I get this messages which makes sense:
Sub query returned more than 1 value. This is not permitted when the
sub query follows =, !=, <, <= , >, >= or when the sub query is used
as an expression. The statement has been terminated.
UPDATE tMain
SET
tMain.FirstReferenceValue = (SELECT ReferenceValue FROM tReference
JOIN tReference on tReference.thePKofMain_FK = tMain.PK_Main
WHERE FK_referenceType =9001649
WHERE FK_referenceType =321)
FROM tReference
WHERE tReference. thePKofMain_FK = tMain.PK_Main
Msg 209, Level 16, State 1, Line 18. Ambiguous column name
'FK_referenceType'. Msg 209, Level 16, State 1, Line 15. Ambiguous
column name 'ReferenceValue'.
OR should I look into doing it in C#?
Some example data:
tReferences:
PK_Reference
123
456
789
FK_ReferenceType:
321
654
987
ReferenceValue
111
a
1
-------------- why I got the first error messages since some reference values are the same
111
c
2
thePKofMain_FK
147
258
369
tReferencesTypes:
PK_ReferenceType
321
654
987
ReferenceName:
FirstReferenceValue
SecondReferenceValue
ThirdReferenceValue
tMain:
PK_Main:
147
258
369
FirstReferenceValue:
Empty
SecondReferenceValue:
Empty
ThirdReferenceValue:
Empty
There is duplicates of ReferenceValues that why the first sql query doesn't work, but even if there are duplicates of the same referenceValue I still need to copy it over to the new table
The second query it accidently typed in WHERE FK_referenceType =9001649 when I was trying to post the question.
Use a Pivot to get the tMain values
INSERT tMain (PK_Main, FirstReferenceValue, SecondReferenceValue, ThirdReferenceValue)
SELECT P.thePKofMain_FK, P.[321], P.[654], P.[987]
FROM (
SELECT FK_ReferenceType, ReferenceValue, thePKofMain_FK
FROM tReference
) T
PIVOT (
MAX(ReferenceValue) FOR FK_ReferenceType IN ([321], [654], [987])
) P
I'm currently working with c# and sql server managment studio:
I have a table like:
+--------+-------------+-------------+------+
| TaskId | Item2(bool) | Item3(bool) | etc… |
+--------+-------------+-------------+------+
I don't know bool column names because there are created dinamically from code (user create them).
Well I insert data when form open, with TaskId and all bools with DEFAULT(0), si I have something like:
+--------------------------------------+-------------+-------------+------+
| TaskId | Item2(bool) | Item3(bool) | etc… |
+--------------------------------------+-------------+-------------+------+
| 9B093907-2072-4F59-A55C-0003CE89EF9E | 0 | 0 | 0 |
+--------------------------------------+-------------+-------------+------+
I want to update booleans, so in c# I create datatable to use User-defined tables:
DataTable checkboxList = new DataTable();
var checkboxNameColumn = checkboxList.Columns.Add("CheckBoxName", typeof(string));
var checkBoxValueColumns = checkboxList.Columns.Add("CheckBoxValue", typeof(bool));
foreach (var c in checkBoxes)
{
var row = checkboxList.NewRow();
row[checkboxNameColumn] = c.Name;
row[checkBoxValueColumns] = c.Checked;
checkboxList.Rows.Add(row);
}
Guid currentUser = new Guid(EBResources.EmpGuid);
Guid currentTaskId = new Guid(TaskId);
db.ExeSQLRedMarkItems($"usp_RedMarkItem_Insert", checkboxList, "#CheckBoxList", currentTaskId, currentUser);
CheckBoxName equals to my column Name and CheckBoxValue is value of that column. So I have my Datatable correct, now I send it to sql as:
User-defined table
CREATE TYPE [HELPER].CheckBoxValues AS TABLE(
CheckBoxName VARCHAR(255) NOT NULL,
CheckBoxValue BIT NOT NULL )
Stored Procedure:
CREATE OR ALTER PROCEDURE [dbo].[usp_RedMarkItem_Insert]
-- Add the parameters for the stored procedure here
#TaskId UNIQUEIDENTIFIER
, #CheckBoxList [Helper].[CheckBoxValues] READONLY
, #CurrentUser UNIQUEIDENTIFIER
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #CurrentCheckboxName VARCHAR(255) = (SELECT
[CheckBoxName]
FROM #CheckBoxList)
UPDATE [m]
SET
#CurrentCheckboxName = [c].[CheckBoxValue]
FROM [RedMarkItems] [m]
JOIN #CheckBoxList [c] ON [c].[CheckBoxName] = #CurrentCheckboxName
WHERE m.TaskId = #TaskId
END
So as you can see I declare #CurrentCheckboxName, but it throws me an error because that select return more than one value:
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
What I need to do to iterate between column names? Regards
you don't need the line below
DECLARE #CurrentCheckboxName VARCHAR(255) = (SELECT
[CheckBoxName]
FROM #CheckBoxList)
you already have this inside #CheckBoxList. You need something like below
UPDATE [m]
SET m.val = [c].Val
JOIN #CheckBoxList [c]
ON [c].[CheckBoxName] = m.CheckBoxName
WHERE m.TaskId = #TaskId
you can get column names from Information_schema
SELECT
TABLE_NAME,
COLUMN_NAME
FROM
INFORMATION_SCHEMA.COLUMNS
Your database design is going to give you a lot of problems. SQL Server works best with pre-defined tables with set numbers of named columns: while you can set up a system to have user-defined field labels, having actual user-defined fields is, in a sense, creating a database that runs on top of a database. You're going to need a lot of infrastructure, that you haven't created yet, to use and manage that.
My suggestion: if your need is for a single row with a collection of user-defined boolean values, store the boolean values as XML.
CREATE TABLE dbo.Task
(
TaskId int,
Checkboxes xml
)
Your XML would be defined something like this (though there are lots of ways you could define it!)
<Checkboxes>
<Checkbox name="User-defined name" value="True" />
<Checkbox name="Some other name" value="False" />
</Checkboxes>
You will still have some challenges -- for example, if you want to pull out all the rows that have a checkbox called "Apple" that had the value true -- but you'll have fewer than you would with an actual user-defined table.
And querying XML in a useful way is, in fact, possible.
I have a stored procedure that currently looks like this:
create procedure zsp_updateTyp5Graph
(
#DayList nvarchar(1000),
#Sales int,
#SearchedUserId int
)
as
update SearchedUserGraphData
set SalesForDay=#Sales
where Day in (SELECT * FROM dbo.SplitString(#DayList)) and SearchedUserId=#SearchedUserId
The daylist parameter looks like following:
0,1,2,3,4,5,6
I have in my SearchedUserGraphData table two columns and 7 records(7 days) that should be updated. For example:
Day Sales
0 5
1 6
2 4
3 3
4 7
5 9
6 11
I have "partially" solved this by passing list of days... But I'm unable to find out how can I pair up this #DayList parameter with sales data...
I have a SplitString function that I've created and looks like this for matching the records in DB:
ALTER FUNCTION [dbo].[splitstring] ( #stringToSplit VARCHAR(MAX) )
RETURNS
#returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN
DECLARE #name NVARCHAR(255)
DECLARE #pos INT
WHILE CHARINDEX(',', #stringToSplit) > 0
BEGIN
SELECT #pos = CHARINDEX(',', #stringToSplit)
SELECT #name = SUBSTRING(#stringToSplit, 1, #pos-1)
INSERT INTO #returnList
SELECT #name
SELECT #stringToSplit = SUBSTRING(#stringToSplit, #pos+1, LEN(#stringToSplit)-#pos)
END
INSERT INTO #returnList
SELECT #stringToSplit
RETURN
END
Now the issue is that I need to somehow pass from my C# application combined list of Days and their corresponding sales, and then update the records all at once, without calling the procedure 7 times to update 7 records (that would be catastrophical from performance standpoint in my eyes)...
Can someone help me out with this?
P.S. Guys, the "best" idea that I get on this one is:
The daylist parameter looks like following:
0,1,2,3,4,5,6
And then sales:
11,22,44,55,66,77,88
This is the way I can pass the sales and days parameters... But then what? I cannot know what sale corresponds to which day...
I could form a key-value pair dictionary string in my C# application maybe like:
{ Day: 1 Sales: 44, Day: 2 Sales: 55 }
this is how I could form the string.. But then I need to break down this string in MSSQL to match => day 1 => update with sales 44 ...
You can create a SalesPerDay type
CREATE TYPE [dbo].[SalesPerDay] AS TABLE (
day INT NOT NULL,
sales INT NOT NULL
);
Then, your proc would look like this
create procedure zsp_updateTyp5Graph
(
#DayList SalesPerDay READONLY,
#SearchedUserId int
)
as
update SearchedUserGraphData
set SalesForDay=dayList.sales
FROM SearchedUserGraphData baseTable
INNER JOIN #DayList dayList ON dayList.day = baseTable.day
WHERE SearchedUserId=#SearchedUserId
And from the C#, you can build a DataTable and send it to the proc.
var table = new DataTable();
table.Columns.Add("day", typeof(int));
table.Columns.Add("sales", typeof(int));
//Add data
table.Rows.Add(new []{1, 200});
table.Rows.Add(new []{2, 200});
//More code
Command.Parameters.AddWithValue("#DayList", table);
Perhaps I'm misunderstanding COALESCE, but in essence, what I'm trying to do is run a select query that if it returns NULL instead of an int, instead return 0 for the purposes of ExecuteScalar().
SQL Server query:
SELECT TOP 1 COALESCE(SeqNo,0)
FROM tblProjectChangeOrder
WHERE ProjectID = XXXXX
ORDER BY SeqNo DESC
If the supplied ProjectID exists in the Change Order table, it returns the expected highest SeqNo. However, if the supplied ProjectID has no existing Change Orders (thus returns NULL for SeqNo), rather than the COALESCE returning 0, I am still getting NULL.
Am I just getting the syntax wrong or is what I want to do possible with COALESCE? The other option I see is to have my ExecuteScalar() pass to a nullable int, then follow that with a ?? to coalesce in my C# codebehind.
As john has mentioned in the comments, COALESCE operates at row level. If a table contains no rows, or a statement returns no rows, then no rows will be returned. Take the simple example below:
CREATE TABLE #Sample (ID int);
SELECT COALESCE(ID, 0)
FROM #Sample;
DROP TABLE #Sample;
Notice that nothing is returned.
Instead, one method is to use a subquery. For your query, that would result in:
SELECT COALESCE(SELECT TOP 1 SeqNo
FROM tblProjectChangeOrder
WHERE ProjectID = XXXXX
ORDER BY SeqNo DESC),0) AS SeqNo;
This also assumes that Seqno has a data type of int; otherwise you're likely to get a conversion error.
My guess is that the null reference exception occures on the code and has nothing to do with the sql query. It might just be that your code is not handling that you return no rows (or no scalar in your case) but you might be trying to access it somewhere in c#.
Show us the line of code that is throwing this exception in c# so we might be able to confirm this.
regards
Edit : From this similar topic
In your c# code you might want to try ("cmd" being your "SqlCommand" object):
int result = 0;
int.TryParse(cmd.ExecuteScalar(), out result);
or in one line
int.TryParse(cmd.ExecuteScalar(), out int result);
I don't know if it is the most suitable solution for you but I hope it is a start.
As covered null and no row are not the same.
This sample covers it.
set nocount on;
select isnull(1, 0)
where 1 = 1;
select isnull(1, 0)
where 1 = 2;
select isnull(null, 0)
where 1 = 1;
select isnull(null, 0)
where 1 = 2;
-----------
1
-----------
-----------
0
-----------
this should work
select top 1 isnull(seq, 0)
from (select null as seq
union all
select max(seq) from tblProjectChangeOrder where ProjectID = XXXXX
) tt
order by seq desc
I am using c# and SQL Server 2008.
I have table like this
id | propertyTypeId | FinishingQualityId | title | Description | features
1 1 2 prop1 propDEsc1 1,3,5,7
2 2 3 prop2 propDEsc2 1,3
3 6 5 prop3 propDEsc3 1
4 5 4 prop4 propDEsc4 3,5
5 4 6 prop5 propDEsc5 5,7
6 4 6 prop6 propDEsc6
and here is my stored code (search in the same table)
create stored procdures propertySearch
as
#Id int = null,
#pageSize float ,
#pageIndex int,
#totalpageCount int output,
#title nvarchar(150) =null ,
#propertyTypeid int = null ,
#finishingqualityid int = null ,
#features nvarchar(max) = null , -- this parameter send like 1,3 ( for example)
begin
select
row_number () as TempId over( order by id) ,
id, title, description,
propertyTypeId, propertyType.name,
finishingQualityId, finishingQuality.Name,
freatures
into #TempTable from property
join propertyType on propertyType.id= property.propertyTypeId
join finishingQuality on finishingQuality.id = property.finishingQualityId
where
property.id = isnull(#id,property.id ) and proprty.PropertyTypeId= isnull(#propertyTypeid,property.propertyTypeId)
select totalpageconunt = ((select count(*) from #TempTable )/#pageSize )
select * from #TempTable where tempid between (#pageindex-1)*#pagesize +1 and (#pageindex*#pageSize)
end
go
I can't here filter the table by feature I sent. This table has too many rows I want to add to this stored code to filter data for example when I send 1,3 in features parameter I want to return row number one and two in the example table I write in this post (want to get the data from table must have the feature I send)
Many thanks for every one helped me and will help
Sending a delimited list of values to match with a delimited value in a column will generally get you into trouble as the only way to do it is to split each value out from the string. (Also why indexing them is pointless)
You should create an additional table containing the id from your property table & a row for each feature;
property_id feature
----------- -------
5 5
5 7
Then matching is much simpler. You can send the procedure the list of features you want to match ideally using a table valued parameter or alternatively a table function.