When I attempt to insert new data in database via PowerShell, it works.
However, if the data is already in database, I get exception.
Someone had similar problem, Catch exception calling "ExecuteNonQuery", but I believe I am using the correct SQL statement in my PowerShell code, where I say SELECT 1
$SQL_insert = "BEGIN
IF NOT EXISTS (SELECT 1
FROM [dbo].[Group_Stats]
WHERE Date_of_Record = CAST(GETDATE() AS DATE)
AND [Group] = '$group')
BEGIN
INSERT INTO [dbo].[Group_Stats] ([Date_of_Record], [Group], [Windows_SEP_11],[Mac_SEP_11],[Windows_SEP_12],[Mac_SEP_12])
VALUES (CAST(GETDATE() AS DATE), REPLACE ('$group', 'My Company\', ''), $win_sep_11, $mac_sep_11, $win_sep_12, $mac_sep_12)
END
END"
Exception
Exception calling "ExecuteNonQuery" with "0" argument(s): "Violation of PRIMARY KEY constraint 'PK_Group_Stats'. Cannot insert duplicate key in object 'dbo.Group_Stats'.
And this is the database
Thanks
You are querying for the untrimmed group name, but when you insert, you call REPLACE() to trim "My Company" off $group. You should instead trim the $group first, then query and insert without calling REPLACE().
Related
I'm trying to write the SQL execute statement below. I'm getting an error in .net saying
An exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll but was not handled in user code
Additional information: Invalid column name 'Survey'
There is no Survey column which is correct, but what is crazy is that it is getting that value from the #SurveyNumber variable. I think my exec code is correct, but maybe I'm not escaping the #SurveyNumber properly?
The #SurveyNumber variable contains this string "Survey - 1234"
#SurveyNumber varchar(50),
#RefIds varchar(max)
AS
Begin
exec('SELECT
Distinct
r.DRAWING,
r.[DESC],
r.REFMEMO,
r.OP_PSI,
r.MAX_PSI,
r.MAX_TEMP,
r.DESIGN,
r.CORR_RATE,
r.MIN_INSP,
r.INSP_LOC,
r.REPL_DATE,
r.LAST_INSP,
r.NEXT_INSP,
r.ALLOW_PSI,
IIf( r.[CF1] is null Or r.[CF1]='''',''Max'', IIf(r.[CF1]=''L'',''Long'',IIf(r.[CF1]=''S'',''Short'',IIf(r.[CF1]=''U'',''User'',''NA''))))AS CF1,
r.[NF2]*1000 as NF2,
r.CF2,
r.V_Last_Insp,
r.V_Next_Insp,
r.V_Concern,
r.V_Memo,
r.V_Report,
r.V_Interval,
r.Insulated,
r.AVG_NEXT_INSP,
r.AVG_REPL_DATE,
r.Scaffolding,
r.Number_Xrays,
r.MIN_RMS,
r.DRAWING_FLAG
From ref r
where r.SurveyNumber = ('+#SurveyNumber+') and r.Id In ('+#RefIds+')
ORDER BY r.NEXT_INSP asc')
End
I have 2 queries, both work fine in SQL Studio:
Query 1:
SELECT [id],[fullname] FROM persons WHERE [id] IN (5802824683954111059,1615647673927737)
Query 2:
IF OBJECT_ID('tempdb..#temp_table_1') IS NOT NULL
TRUNCATE TABLE #temp_table_1
ELSE
CREATE TABLE #temp_table_1 ( [key] bigint primary key );
INSERT INTO #temp_table_1 ([key]) VALUES (5802824683954111059),(1615647673927737);
SELECT [id],[fullname] FROM persons WHERE [id] IN (SELECT [key] FROM #temp_table_1)
But when I execute these queries using ADODB.Recordset.Open() method, only the first query returns valid result.
For the second query Recordset.EOF property throws "Operation is not allowed when the object is closed" error.
What is wrong with the second query? Does ADODB support multiple statements in a query?
The sample code demonstrating the problem:
conn = new ActiveXObject( 'ADODB.Connection' );
conn.Open( 'Provider=SQLOLEDB;Integrated Security=SSPI;Server=mt;Database=test;Integrated Security=SSPI' );
rs = new ActiveXObject( 'ADODB.Recordset' );
//sqlQuery = "SELECT [id],[fullname] FROM persons WHERE [id] IN (5802824683954111059,1615647673927737)";
sqlQuery = "IF OBJECT_ID('tempdb..#temp_table_1') IS NOT NULL\r\n\
TRUNCATE TABLE #temp_table_1\r\n\
ELSE\r\n\
CREATE TABLE #temp_table_1 ( [key] bigint primary key );\r\n\
INSERT INTO #temp_table_1 ([key]) VALUES (5802824683954111059),(1615647673927737);\r\n\
SELECT [id],[fullname] FROM persons WHERE [id] IN (SELECT [key] FROM #temp_table_1)";
rs.Open( sqlQuery, conn );
while ( ! rs.EOF )
{
alert( rs.Fields( 'fullname' ) );
rs.MoveNext();
}
Try either adding SET NOCOUNT ON to your T-SQL batch or invoke the Recordset.NextResult method after processing the results of the SELECT query.
SET NOCOUNT ON instructs SQL Server suppress DONE_IN_PROC TDS protocol messages (row counts), which classic ADO has the nasty habit of returning as closed empty recordsets with no columns. Failure to consume these with NextResult will prevent the entire T-SQL batch from running to completion.
It's a good practice to invoke NextResult until the method returns False as that will ensure the entire batch runs to completion regardless of the SET NOCOUNT session setting. Note that this technique also applies to other client APIs (ADO.NET, JDBC, etc), although the exact method to consume results differ as well as the symptoms (partial result sets, undetected exceptions).
I'm unable to find a solution online for my question. If it is even possible, how do I write an SQL Insert statement that uses parameter values as well as selecting a value from another table.
Example:
"INSERT INTO Users (user_name, user_csn, user_adid, user_contact, user_adminpriviledge, user_datestart, user_active, user_team)
VALUES (#username, #usercsn, #useradid, #usercontact, #userauth, #userstart, #useractive, #userteam = (SELECT team_id FROM teaminfo WHERE team_name = '" & ddlAddTeam.SelectedValue & "'))"
I understand that the example is wrong, just trying my best to represent what I'm looking for in code.
Also another question would be regarding aliasing and datareaders. I seem to be unable to do "reader("column_name")" for aliased column names?
Example:
query = "SELECT u.*, t.team_name FROM Users u
JOIN teaminfo t ON u.user_team = t.team_id WHERE user_csn = '" & GV.userCSN & "'"
I tried to use
reader("u.user_name")
but failed as well.
You need other syntax of insert operation: INSERT INTO ... SELECT ... FROM ...:
INSERT INTO Users (user_name, user_csn, user_adid, user_contact, user_adminpriviledge, user_datestart, user_active, user_team)
SELECT #username, #usercsn, #useradid, #usercontact, #userauth, #userstart, #useractive, team_id --<--not here's your column
FROM teaminfo
WHERE team_name = #param
Also, it looks like it's .NET (C# or VB code), so you you are prone to SQL injection concatenating you string with parameters!
In my SQL I already put #param in proper place, then with SqlCommand you are probably using, you have to call method Addon SqlCommand.Paramteres collection, and then supplly it with value of ddlAddTeam.SelectedValue.
Try this code:
Using connection = New SqlConnection("connString")
Using com = New SqlCommand
com.Connection = connection
com.CommandText = "INSERT INTO Users (user_name, user_csn, user_adid, user_contact, user_adminpriviledge, user_datestart, user_active, user_team)
Select #username, #usercsn, #useradid, #usercontact, #userauth, #userstart, #useractive, team_id --<--Not here's your column
From teaminfo
Where team_name = #param"
com.Parameters.Add("#param", SqlDbType.VarChar).Value = ddlAddTeam.SelectedValue
connection.Open()
End Using
End Using
And for column alises: in data reader you use column aliases without table name (u before the dot in ou example). Try to give aliases to all your columns to avoid such problems.
The data source for an INSERT statement can be a SELECT statement—see the <dml_table_source> part of the statement definition at the linked page—and a SELECT statement can include parameters in the select list. Here's a simple example:
declare #Target table (Id bigint, Datum char(1));
declare #Source table (Id bigint);
declare #Datum char(1) = 'X';
insert #Source values (1);
insert #Target
select
Id = S.Id, -- Value from another table
Datum = #Datum -- Parameter
from
#Source S;
There are more examples at the page linked above; scroll down to the "Inserting Data From Other Tables" section header.
Also, if you're going to build a query in (C#?) code as you've shown in your example, you should really pass any arguments as parameters rather than trying to build them directly into the query text. Read up on SQL injection attacks to see why.
Your INSERT query should be like
"INSERT INTO Users (user_name, user_csn, user_adid, user_contact, user_adminpriviledge, user_datestart, user_active, user_team)
VALUES (#username, #usercsn, #useradid, #usercontact, #userauth, #userstart, #useractive, (SELECT team_id FROM teaminfo WHERE team_name = #userteam ))"
Second when fetching from reader it should be like :
reader("user_name") // I am not sure about this. You can put break point and open the object in watch window
Assuming my table consist of two columns ID and Name.
And assume I have my stored procedure working on vb.net that inserts rows into the database.
But my system needs to check if an ID entered in a textbox already exists in the database when ADD button is click.
CREATE PROCEDURE AddOfficeEquipmentProfile
(
#OE_ID varchar(11),
#OE_Category char(3) =NULL,
#OE_SubCategory char(3)= NULL,
#OE_Name varchar(35)=NULL,
#OE_User varchar(35)=NULL,
#OE_Brand varchar(15)=NULL,
#OE_Model varchar(35)=NULL,
#OE_Specs varchar(1000)=NULL,
#OE_SerialNo varchar(35)=NULL,
#OE_PropertyNo varchar(35)=NULL,
#OE_MacAddress varchar(100)=NULL,
#OE_Static_IP varchar(15)=NULL,
#OE_Vendor varchar(35)=NULL,
#OE_PurchaseDate smalldatetime,
#OE_WarrantyInclusiveYear int=NULL,
#OE_WarrantyStatus char(2)= NULL,
#OE_Status varchar(15)=NULL,
#OE_Dept_Code char(3)= NULL,
#OE_Location_Code char(8)= NULL,
#OE_Remarks varchar(1000)= NULL
)
AS
INSERT INTO tblOfficeEquipmentProfile (OE_ID, OE_Category, OE_SubCategory, OE_Name, OE_User, OE_Brand, OE_Model, OE_Specs, OE_SerialNo,
OE_PropertyNo, OE_MacAddress, OE_Static_IP, OE_Vendor, OE_PurchaseDate, OE_WarrantyInclusiveYear, OE_WarrantyStatus, OE_Status, OE_Dept_Code,
OE_Location_Code, OE_Remarks )
VALUES (#OE_ID, #OE_Category, #OE_SubCategory, #OE_Name, #OE_User, #OE_Brand, #OE_Model,
#OE_Specs, #OE_SerialNo, #OE_PropertyNo, #OE_MacAddress, #OE_Static_IP, #OE_Vendor, #OE_PurchaseDate, #OE_WarrantyInclusiveYear, #OE_WarrantyStatus,
#OE_Status, #OE_Dept_Code, #OE_Location_Code, #OE_Remarks)
GO
few things you can do
make ID column as primary key, when insert you will get exception if duplicated
You can use auto increment ID, then you don't need to check ID exit or not. database will handle that
If you can't do above, run select statement or stored procedure to check whether id exist or not.
If this is for SQL Server and you're using a stored procedure - just try something like this:
CREATE PROCEDURE AddOfficeEquipmentProfile
(
#OE_ID varchar(11),
..... all your other parameters here.....
)
AS
IF NOT EXISTS (SELECT * FROM dbo.tblOfficeEquipmentProfile WHERE OE_ID = #OE_ID)
INSERT INTO dbo.tblOfficeEquipmentProfile(.... list of columns.....)
VALUES (......list of values................)
Assuming that OE_ID is your primary key and will be unique. Just check if that #OE_ID doesn't exist yet, and if it doesn't - insert the data. If it exists - don't do anything.
Building on the answer from #marc_s. In order to show a message to the user in case there already is a row in the database with the same id, you can check the number of affected rows from the query execution result.
This assumes that the stored procedure only inserts the row if the id is not present and does not emit any errors/exceptions.
Using ADO.NET (with an existing command executing the stored procedure):
Dim affectedRows as Integer = command.ExecuteNonQuery()
If affectedRows = 0 Then
'Handle the error here
MessageBox.Show("There is already a Profile with the supplied id")
Else
'Insert was made
End If
Check the following article to create a SP finding duplicate rows in any table:
http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server
My program is inserting into a table like this...
CREATE TABLE [DBO].[MYTABLE] (
ID [INT] IDENTITY (1,1),
DATE_TIME [DATETIME],
NOTES [VARCHAR] (100))
using the following code...
database_connection = New ADODB.Connection
' ...code to connect...
database_connection.IsolationLevel = ADODB.IsolationLevelEnum.adXactSerializable
database_connection.BeginTrans
command_string = "INSERT INTO [MySchema].[dbo].[MyTable] (NOTES) VALUES ('sometext')"
database_connection.Execute(command_string)
command_string = "SELECT MAX([id]) as max_id FROM [MySchema].[dbo].[MyTable]"
Dim record_set As ADODB.Recordset = New ADODB.Recordset
record_set.CursorLocation = ADODB.CursorLocationEnum.adUseClient
record_set.Open(command_string, database_connection, ADODB.CursorTypeEnum.adOpenStatic, , ADODB.CommandTypeEnum.adCmdText)
record_set.MoveLast
new_id = CInt(record_set.Fields("id").Value)
database_connection.CommitTrans
Occasionally this code is executed by two different programs simultaneously (close enough in time that the date_time values are identical), and although there are two rows visible in MyTable, both programs are running with the same new_id.
Although I appreciate I should probably be using SCOPE_IDENTITY here (and I'll try it in a minute), I was under the impression that the SERIALIZABLE transaction would prevent this from happening. Does anyone know why this duplication is occurring, and if SCOPE_INDENTITY will fix the problem?
You definitely need to use SCOPE_IDENTITY, but in the same query as INSERT.
When 2 clients insert data in a same table at same time -> the second query will return Max(id) of 2nd inserted value.
INSERT INTO [MySchema].[dbo].[MyTable] (NOTES) VALUES ('sometext')
SELECT SCOPE_IDENTITY()
the easiest way would be opening the recordset with following command, without previous execute
INSERT INTO [MySchema].[dbo].[MyTable] (NOTES)
OUTPUT inserted.id
VALUES ('sometext')