SQL Insert parameter value and value from another table - sql-server

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

Related

How to drop duplicate records in the SQL Server using Python?

I have a .csv file and it gets updated every day. Below is the example of my .csv file
I am pushing this .csv file into SQL Server using Python. My script reads the .csv file and uploads it into a SQL Server database.
This is my Python script:
import pandas as pd
import pyodbc
df = pd.read_csv ("C:/Users/Dhilip/Downloads/test.csv")
print(df)
conn = pyodbc.connect('Driver={SQL Server};'
'Server=DESKTOP-7FCK7FG;'
'Database=test;'
'Trusted_Connection=yes;')
cursor = conn.cursor()
#cursor.execute('CREATE TABLE people_info (Name nvarchar(50), Country nvarchar(50), Age int)')
for row in df.itertuples():
cursor.execute('''
INSERT INTO test.dbo.people_info (Name, Country, Age)
VALUES (?,?,?)
''',
row.Name,
row.Country,
row.Age
)
conn.commit()
The script is working fine. I am trying to automate my Python script using batch file and task scheduler, and it's working fine. However, whenever I add new data in the .csv file and SQL Server gets updated with new data and the same time it prints the old data multiple times.
Example, if I add new record called Israel, the output appears in SQL Server as below
I need output as below,
Can anyone advise me the change I need to do in the above python script?
You can use below query in your python script. if Not exists will check if the record already exists based on the condition in where clause and if record exists then it will go to else statement where you can update or do anything.
checking for existing records in database works faster than checking using python script.
if not exists (select * from Table where Name = '')
begin
insert into Table values('b', 'Japan', 70)
end
else
begin
update Table set Age=54, Country='Korea' where Name = 'A'
end
to find existing duplicate records then use the below query
select Name, count(Name) as dup_count from Table
group by Name having COUNT(Name) > 1
I find duplicates like this
def find_duplicates(table_name):
"""
find duplicates inside table
:param table_name:
:return:
"""
connection = sqlite3.connect("./k_db.db")
cursor = connection.cursor()
findduplicates = """ SELECT a.*
FROM {} a
JOIN (
SELECT shot, seq, lower(user), date_time,written_by, COUNT(*)
FROM {}
GROUP BY shot, seq, lower(user), date_time,written_by
HAVING count(*) > 1 ) b
ON a.shot = b.shot
AND a.seq = b.seq
AND a.date_time = b.date_time
AND a.written_by = b.written_by
ORDER BY a.shot;""".format(
table_name, table_name
)
# print(findduplicates)
cursor.execute(findduplicates)
connection.commit()
records = cursor.fetchall()
cursor.close()
connection.close()
You could rephrase your insert such that it checks for existence of the tuple before inserting:
for row in df.itertuples():
cursor.execute('''
INSERT INTO test.dbo.people_info (Name, Country, Age)
SELECT ?, ?, ?
WHERE NOT EXISTS (SELECT 1 FROM test.dbo.people_info
WHERE Name = ? AND Country = ? AND Age = ?)
''', (row.Name, row.Country, row.Age, row.Name, row.Country, row.Age,))
conn.commit()
An alternative to the above would be to add a unique index on (Name, Country, Age). Then, your duplicate insert attempts would fail and generate an error.

F# FSharp.Data.SqlClient not recognizing multiple return tables from Stored Procedure

I am not sure if this is possible but I have not been able to come across clear documentation for this use case. I am using F# 4 and the FSharp.Data.SqlClient library to connect to SQL Server 2016. I am wanting to call a stored procedure that returns multiple tables and turn those tables into the corresponding records. In this case the first table is made up of items and the second table is made up of customers.
My instinct is that it should look something like this:
let items, customers = cmd.Execute()
My gut is that items would be an IEnumerable<item> and customers would be an IEnumerable<customer> where item and customer are both Record types. What it appears is happening though is that FSharp.Data.SqlClient is only seeing the first returned table from the stored procedure. I am working on a SQL Server 2016 Developer instance. Here is the T-SQL to setup the example:
create table Item (
ItemID int identity(1, 1) primary key,
ItemName nvarchar(50)
)
go
create table Customer (
CustomerID int identity(1, 1) primary key,
CustomerName nvarchar(50)
)
go
insert into Item (ItemName) values ('A');
insert into Item (ItemName) values ('B');
insert into Item (ItemName) values ('C');
insert into Customer (CustomerName) values ('Gary');
insert into Customer (CustomerName) values ('Sergei');
insert into Customer (CustomerName) values ('Elise');
go
create procedure dbo.ExampleProcedure
as
begin
set nocount on;
select
ItemID,
ItemName
from Item
select
CustomerID,
CustomerName
from Customer
end;
And here is the F# script that I am testing with. It shows what I would like to be able to do but I get a compile error on the last line:
#r "../packages/FSharp.Data.SqlClient.1.8.2/lib/net40/FSharp.Data.SqlClient.dll"
#r "../packages/FSharp.Data.2.3.2/lib/net40/FSharp.Data.dll"
#r "System.Xml.Linq.dll"
open FSharp.Data
[<Literal>]
let connStr =
"Data Source=**connection string**;"
type queryExample = SqlProgrammabilityProvider<connStr>
do
use cmd = new queryExample.dbo.ExampleProcedure(connStr)
let items, customers = cmd.Execute()
I am wanting items to correspond to the first returned table and customers to correspond to the second returned table. The intellisense suggests that FSharp.Data.SqlClient is only seeing the first table. When I hover over cmd.Execute() the popup says "This expression was expected to have type 'a*'b but here has type System.Collections.Generic.IEnumerable<SqlProgrammabilityProvider<...>.dbo.ExampleProcedure.Record>". If I do the following I get access to the Items query in the stored procedure:
// Learn more about F# at http://fsharp.org. See the 'F# Tutorial' project
// for more guidance on F# programming.
#r "../packages/FSharp.Data.SqlClient.1.8.2/lib/net40/FSharp.Data.SqlClient.dll"
#r "../packages/FSharp.Data.2.3.2/lib/net40/FSharp.Data.dll"
#r "System.Xml.Linq.dll"
open FSharp.Data
[<Literal>]
let connStr =
"Data Source=**connection string**;"
type queryExample = SqlProgrammabilityProvider<connStr>
do
use cmd = new queryExample.dbo.ExampleProcedure(connStr)
for item in cmd.Execute() do
printfn "%A" item.ItemID
Is this even possible? Is my approach wrong? I could not find clear documentation on this use case but I thought it would be common enough it would be covered.
Update
Just to clarify what I am trying to achieve I am showing how I solve this in C#. In C# I create a DataSet object and populate it with the results of the Stored Procedure. From there I pick out the individual tables to work with. After extracting the tables I then use LINQ to transform the rows into the corresponding objects. It often looks something like the following:
using System.Data;
using System.Data.SqlClient;
var connStr = "**connection string**"
var sqlConnection = new SqlConnection(connStr );
var sqlCommand = new SqlCommand("ExampleProcedure", sqlConnection);
sqlCommand.CommandType = CommandType.StoredProcedure;
var dataSet = new DataSet();
var adapter = new SqlDataAdapter(sqlCommand);
adapter.Fill(dataSet);
var itemsTable = dataSet.Tables[0];
// Turn the itemsTable into a List<Item> using LINQ here
var customersTable = dataSet.Tables[1];
// Turn the customersTable into List<Customer> using LINQ here
I find this to be overly verbose for such a simple thing as extracting the individual tables but perhaps I am too sensitive to code clutter. I know that F# must have a more elegant and terse way to express this.
I don't know F#, however this is a data access problem.
When a stored procedure returns multiple resultsets, you need to access they in sequence, one by one.
cmd.ExecuteReader() returns an instance of a datareader pointing to the first resultset. You need to process this resultset, may be filling a list with instances of a custom class, than you call the method "NextResult" and you will have access to the next resultset and so on.
A reference for the method "NextResult": https://msdn.microsoft.com/pt-br/library/system.data.sqlclient.sqldatareader.nextresult(v=vs.110).aspx

Why is the same value on IDENTITY column being returned to two inserters?

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')

How to retrieve the value of uniqueidentifier generated while insert in Delphi ADO?

Suppose I generate the PK for my SQL Server DB table with the help of newid() function. In Java I can do something like this:
...
String query = "DECLARE #newGuid uniqueidentifier "+
"SET #newGuid = newid() "+
"INSERT INTO myTable(id, stringval) "+
"VALUES (#newGuid, "Hello") "+
"SELECT uid FROM #newGuid";
PreparedStatement ps = conn.prepareStatement(query);
ResultSet rs = ps.executeQuery();
String uid = rs.getString("uid");
But when I try to make that with Delphi+ADO I get stuck cause ADO can either get data from DB (Open method of AdoQuery) or put data to DB (ExecSQL method). So I can't insert new value to the table and get the parameter value afterwards.
You could solve this problem atleast in two ways.
You can put both of your SQL queries into one string (just like you have in your example) and call TADOQuery.Open or TADOQuery.Active := True. it doesn't matter that you have INSERT statement there as long as query returns something.
You can define parameter's direction as pdOutput in ADOQuery.Parameters collection and read value of that parameter after executing the query.
You are treating #newGuid as if it was a table. Your last row in the query should be:
SELECT #newGuid as uid

how to insert record set value in to the table?

Am having 6 fields in the record set
I want to insert into the table? How can I insert.
Used Query
INSERT INTO table values (recordset (0), recordset (1) ….. recordset (6))
But It showing Undefined function “recordset”
Please how to insert record set value in to the table?
Dim cmdCommand As New ADODB.Command
If recordSet.EOF = False Then
recordSet.MoveFirst
cmdCommand.CommandText = "insert into table ( field1) values ( " + recordSet.Fields(0) + ")"
cmdCommand.Execute()
recordSet.MoveNext
Loop Until recordSet.EOF = True
Keep in mind that you will need quotes in varchar fields
Konstantinos gives a good answer, but you just need to be careful of the potential for SQL Injection issues.
The simplest fix would be to just replace any single apostrophes with two.
.CommandText = "insert into table (field1) values ( '" & Replace(recordSet.Fields(0), "'", "''") & "')"
It sounds like you're attempting to INSERT multiple records using a single statement (one INSERT for 6 records instead of 6 INSERT for 1 record each). If that's the case, the INSERT syntax fully supports it.
Here's an example:
INSERT INTO MyTable
(row1, row2)
SELECT
value1, value2
FROM
OtherTable
When you look at it like this, you can basically take any SELECT statement and put the INSERT clause on top of it. Of course, the column names need to line up correctly for it to work.
You may insert data into database using the codeigniter Framework.
Database
Table Name : user
Fields Name : name , email
Insert a record using codeigniter:
//storing data **record** into an **Array**
$data(
'name' => 'Rudra',
'email' => 'rud.test#gmail.com',
)
//Inserting Array into Database Table Name : **user**
$this->db->insert('user',$data);
Try with the recordsetname.fields("field_name") and check that the recorsetname variable was defined. You can also use the syntax recordsetname!field_name.

Resources