Writing Rows to SQL Database with Primary Key in WinCC RT Professional
1. Overview
WinCC RT Professional (TIA Portal) exposes VBScript as its primary automation language for runtime actions, schedulers, and faceplate events. When the runtime must persist process values, alarms, or audit data to a relational database, the typical pattern is an ADODB.Connection opened against an ODBC DSN, followed by an INSERT statement. The most common failure mode encountered in the field is the Primary Key constraint: a column declared PRIMARY KEY with no IDENTITY definition or default value will reject the INSERT if the script does not supply a unique value, and will silently fail or raise error -2147217864 (violation of PRIMARY KEY constraint) if a duplicate is supplied.
This tutorial walks through configuring a working write path from WinCC RT Professional into a SQL Server table that uses a Primary Key, including the ODBC configuration, the ADODB connection string, the VBScript insert logic, and the canonical Siemens "Database_1" project pattern. The MySQL equivalent is noted where the syntax diverges.
Database_1 example project ships with WinCC Professional V17/V18/V19 and uses the native OLE DB provider. The techniques below are valid for V16 onward.2. Prerequisites
| Component | Version / Spec | Notes |
|---|---|---|
| WinCC RT Professional | V16, V17, V18, V19 | Tested on V18 Update 4; V19 has identical scripting surface |
| SQL Server | 2016, 2019, 2022 | Express edition is sufficient for single-station logging |
| ODBC Driver | ODBC Driver 17 for SQL Server (or 18) | Native client (SQLNCLI) is deprecated; use msodbcsql17/18 |
| SQL Server Management Studio | 19.x or 20.x | Used to create the table and verify row inserts |
| User account | db_datareader + db_datawriter on target DB | Avoid sa; use a least-privilege login |
| Network | TCP/1433 open between HMI station and DB server | Use SQL Server Configuration Manager to confirm |
Confirm scripting is enabled in the runtime project: Project > Runtime settings > Scripts > Allow VBScript. Without this flag, the scheduler and event-driven VBS actions will be ignored at runtime.
3. Configure the ODBC Data Source
On the WinCC RT Professional station, open ODBC Data Sources (64-bit) from the Windows Administrative Tools menu. SQL Server is a 64-bit application; using the 32-bit ODBC panel will produce "Architecture mismatch" errors when the runtime attempts to load the driver.
- Switch to the System DSN tab and click Add.
- Select ODBC Driver 17 for SQL Server and click Finish.
- Name:
WinCC_SQL(this is the DSN referenced by the connection string). - Description:
WinCC RT Professional logging target. - Server: enter the SQL Server instance, for example
SVR-PROD\SQLEXPRESSorSVR-PROD,1433for a non-default port. - Authentication: choose SQL Server Authentication for service accounts, or Windows Integrated if the WinCC runtime service runs as a domain user with the required SQL login.
- Set the default database to your target, e.g.
ProcessData. - Test the data source. A successful test confirms the driver, network, and credentials all align before you touch WinCC.
SiemensSIMATICWinCCRTPro) is the one that authenticates, not the logged-in operator. Grant the service account the SQL login, not the operator account.4. Build the Table with a Primary Key
In SQL Server Management Studio, create a table whose first column is the Primary Key. The two viable strategies for auto-generating unique values are IDENTITY (SQL Server) and AUTO_INCREMENT (MySQL). For SCADA logs, the IDENTITY approach is preferred because the VBS script can omit the PK column from the column list.
CREATE TABLE dbo.ProcessEvents (
EventID INT IDENTITY(1,1) NOT NULL,
TagName NVARCHAR(128) NOT NULL,
TagValue REAL NULL,
QualityCode SMALLINT NULL,
EventTime DATETIME2(3) NOT NULL
CONSTRAINT DF_ProcessEvents_Time DEFAULT (SYSUTCDATETIME()),
CONSTRAINT PK_ProcessEvents PRIMARY KEY CLUSTERED (EventID)
);
Key points:
-
IDENTITY(1,1)causes SQL Server to populateEventIDautomatically on eachINSERT. The script must NOT supply a value for this column, or it will fail with error 544 (Cannot insert explicit value for identity column when IDENTITY_INSERT is OFF). -
SYSUTCDATETIME()as a default removes the need for the script to bind a timestamp; useful for multi-station rollouts where each HMI may be in a different timezone. - The
PRIMARY KEY CLUSTEREDclause is what makes the column a real key; without it, aNOT NULL UNIQUEconstraint is not a Primary Key and behaves differently in replication and indexing.
For more details on Primary Key semantics and the permissions needed to create one, see the Microsoft Learn reference: Create Primary Keys in SQL Server.
5. Primary Key Strategy Comparison
| Strategy | DBMS | Script supplies PK? | Pros | Cons |
|---|---|---|---|---|
IDENTITY(1,1) |
SQL Server | No | Automatic, gap-free sequence, no race conditions | Identity values can be reused after rollback in some edge cases |
SEQUENCE + default |
SQL Server 2012+ | No | Reusable across tables, decoupled from column | More setup; requires NEXT VALUE FOR in default |
UNIQUEIDENTIFIER + NEWID() default |
SQL Server | No | Globally unique, merge-friendly across sites | 16 bytes per row, fragmented clustered index |
ROWID / GUID
|
MySQL | No | Auto-populated | MySQL syntax differs; use INSERT ... per MySQL 9.7 INSERT reference
|
| Manual PK from script | Either | Yes | Full control, deterministic IDs | Race conditions on multi-station, must query MAX first |
For nearly all WinCC logging scenarios, IDENTITY(1,1) is the correct choice. Manual PK assignment is only justified when the operator must enter or scan a known identifier (work order number, batch ID).
6. The Standard "Database_1" Example Project
WinCC Professional ships a reference project demonstrating OLE DB connectivity, located at:
C:\Program Files\Siemens\Automation\Portal V18\Data\WinCC\Examples\Database_1
The example uses the VBScript pattern below. Two objects are required: an ADODB.Connection for the session and an ADODB.Recordset for the row. WinCC also supports command-style execution via Connection.Execute(SQL) for pure inserts that do not need to return data.
7. ADODB.Connection and Connection String
The connection string binds the script to the DSN configured in Section 3. Two connection string variants are shown; pick the one that matches the authentication method chosen in the DSN.
' Variant A: SQL Server authentication (preferred for service accounts)
strConn = "Provider=MSDASQL;" & _
"DSN=WinCC_SQL;" & _
"UID=scada_writer;" & _
"PWD=Str0ng!Pass;" & _
"Database=ProcessData;"
' Variant B: Windows Integrated (service account authenticates)
strConn = "Provider=MSDASQL;" & _
"DSN=WinCC_SQL;" & _
"Trusted_Connection=Yes;" & _
"Database=ProcessData;"
Always declare the connection object with explicit cleanup. A leaked connection will exhaust the SQL Server connection pool after roughly 100 open handles, and WinCC will start logging Error: -2147467259 [DBNETLIB] errors.
Dim conn, rs, strSQL, strConn
Set conn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
strConn = "Provider=MSDASQL;DSN=WinCC_SQL;" & _
"UID=scada_writer;PWD=Str0ng!Pass;Database=ProcessData;"
On Error Resume Next
conn.Open strConn
If Err.Number <> 0 Then
HMIRuntime.Trace "DB open failed: " & Err.Number & " " & Err.Description & vbCrLf
Err.Clear
Exit Sub
End If
On Error Goto 0
8. The INSERT Script for a Table with a Primary Key
This is the canonical insert for a table whose first column is EventID INT IDENTITY(1,1). Note that the column list omits EventID entirely; this is the only correct way to write to an IDENTITY column when IDENTITY_INSERT is OFF.
Dim strSQL
strSQL = "INSERT INTO dbo.ProcessEvents " & _
"(TagName, TagValue, QualityCode) " & _
"VALUES ('" & Replace(SmartTags("TagName"),"'","''") & "', " & _
CStr(SmartTags("TagValue")) & ", " & _
CStr(SmartTags("QualityCode")) & ");"
On Error Resume Next
conn.Execute strSQL, , adExecuteNoRecords
If Err.Number <> 0 Then
HMIRuntime.Trace "DB insert failed: " & Err.Number & " " & Err.Description & vbCrLf
Err.Clear
Else
HMIRuntime.Trace "DB insert OK, rows affected: " & conn.Execute("SELECT @@IDENTITY").Fields(0).Value & vbCrLf
End If
On Error Goto 0
Three details resolve the most common failures from the field:
-
No
WHEREclause on anINSERT:INSERTstatements never have aWHERE. The original question describes a script that "will not insert a new row" when theWHERE RowNo is Xclause is removed; this is a copy/paste artifact from anUPDATEexample in the Siemens sample. Delete theWHEREline and the insert will succeed. -
Single-quote escaping: the
Replace(...,"'","''")doubles any single quote inside the tag value. Without it, a tag value ofO'Brienwould break the SQL and cause a syntax error. -
Numeric coercion: wrap numeric tags with
CStr()to force a string concatenation; unconvertedEmptyvalues produceNULLin the resulting text and SQL Server raises error 245 (Conversion failed).
For MySQL targets, the equivalent pattern is documented in the MySQL 9.7 INSERT statement reference. Use INSERT ... ON DUPLICATE KEY UPDATE if the application legitimately needs upsert behavior against a UNIQUE or PRIMARY KEY column.
9. Closing the Connection and Lifecycle
Open the connection at the start of an action and close it at the end. For long-running schedulers that fire every second, cache the connection object at module level and reopen on error. The classic mistake is opening a new connection on every tag change, which leaks handles within minutes.
' Cleanup at end of action
If rs.State = adStateOpen Then rs.Close
If conn.State = adStateOpen Then conn.Close
Set rs = Nothing
Set conn = Nothing
For 24/7 logging, the recommended pattern is a global ADODB.Connection in a runtime module that:
- Opens on RT startup via a "Start" event.
- Reconnects automatically if
conn.State <> adStateOpenat the start of each write. - Closes only on RT shutdown.
10. Verification Procedure
- In SQL Server Management Studio, expand the target database, then Tables > dbo.ProcessEvents. Right-click and choose Select Top 1000 Rows to confirm the table exists with the expected columns and Primary Key icon.
- In TIA Portal, open the WinCC RT Professional project and call the insert action from a button or scheduler.
- Refresh the SSMS view. A new row should appear with an auto-generated
EventIDone greater than the previous row. - Check the WinCC runtime trace window (ApDiag.exe or Runtime > Trace) for the line
DB insert OK. Any error number starting with-2147indicates an ADODB-layer failure; anything else is a SQL Server-side error. - To test the Primary Key path, manually insert a row with a known
EventIDvia SSMS usingSET IDENTITY_INSERT dbo.ProcessEvents ON, then attempt a script insert with the sameEventID. The script should fail with error 2627 (Violation of PRIMARY KEY constraint). This confirms your error-handling path is wired correctly.
11. Troubleshooting Matrix
| Symptom | Likely Cause | Fix |
|---|---|---|
| Script does nothing, no error, no row |
INSERT statement includes a stray WHERE clause from an UPDATE template |
Remove the WHERE; INSERT has no WHERE
|
| Error -2147217864 / Msg 2627 | Script supplies a value for the IDENTITY PK column | Remove the PK column from the INSERT column list |
| Error -2147217900 / Msg 544 | Script supplies a value for the IDENTITY column when IDENTITY_INSERT is OFF |
Same as above; never write to IDENTITY manually |
| Error -2147467259 / Msg 53 | ODBC DSN not visible to the WinCC service account | Use System DSN, not User DSN; confirm 64-bit ODBC panel |
| Error -2147217865 / Msg 245 | Tag value contains an unescaped single quote or non-numeric data in a numeric column | Apply Replace(val,"'","''") and CStr() for numerics |
| Connection works once, fails on second call | Connection not closed; pool exhausted | Always conn.Close + Set conn = Nothing
|
| "Cannot find the object dbo.ProcessEvents" | Wrong default database in the DSN, or missing dbo. schema prefix |
Reconfigure DSN default DB or qualify the table name with dbo.
|
| Inserts succeed in SSMS, fail from WinCC | WinCC service runs as LocalSystem which cannot use Integrated auth to a remote SQL |
Switch the DSN to SQL auth, or run the WinCC service as a domain user with a SQL login |
| Slow performance, SQL Server CPU at 100% | Reopening connection per write, missing index on EventTime
|
Cache the connection; add a nonclustered index on EventTime
|
12. Field-Proven Tips and Caveats
-
Do not leave a connection open "to SQL2008 R2 on boot up" as a permanent pattern. While some legacy SCADA packages do this, in WinCC RT Professional it is safer to use a single cached connection that reconnects on error. A permanently open connection that is severed by a network blip will not auto-recover unless the script watches
conn.State. - Do not modify the bundled "Database_1" project files in place. Copy the project, rename the folder, then change the DSN and SQL inside the copy. This keeps the example intact as a known-good reference.
-
Use the OLE DB provider
MSOLEDBSQLfor new deployments on SQL Server 2019+. The olderSQLOLEDBprovider is deprecated and removed from the OS in recent Windows builds. TheProvider=MSDASQL;string used above is a thin wrapper over the ODBC driver and is the most compatible across WinCC versions. -
Parameterize when possible. While this tutorial uses string concatenation for clarity, a production deployment should use
ADODB.Commandwith parameters to eliminate SQL injection risk and quote-handling bugs entirely. -
Set a query timeout.
conn.CommandTimeout = 10(seconds) prevents a hung connection from blocking the scheduler for minutes. -
Trace to file, not just to the diagnostic buffer. Use
HMIRuntime.Tracewith a configured trace path under Computer > Properties > Runtime > Trace for post-incident analysis.
conn.Execute in On Error Resume Next with explicit error handling, and never call End from inside the database action. Alarms or process interlocks that depend on a confirmed log write should use a separate acknowledgement path; the database write is a best-effort audit, not a control signal.13. Frequently Asked Questions
Why does my INSERT script fail when I add a WHERE clause?
INSERT statements do not accept a WHERE clause. If you copied a template from an UPDATE example, remove the WHERE line entirely. The canonical insert form is INSERT INTO table (col1, col2) VALUES (val1, val2); with no predicate.
How do I write to a table whose Primary Key is an IDENTITY column?
Omit the IDENTITY column from the INSERT column list. SQL Server auto-populates it on each insert. Supplying a value manually causes error 544 (IDENTITY_INSERT is OFF) or 2627 (duplicate key) depending on whether the value is unique.
Which ODBC driver should I install for WinCC RT Professional on Windows 10/11?
Use ODBC Driver 17 for SQL Server or ODBC Driver 18 for SQL Server (msodbcsql17 / msodbcsql18). The legacy SQL Native Client (SQLNCLI) is deprecated and not shipped with current Windows builds. Install the 64-bit driver because WinCC RT Professional is a 64-bit application.
Should I leave the database connection open permanently for performance?
Cache a single ADODB.Connection in a runtime module and reconnect on error rather than opening/closing per write. A permanently open connection that is severed by a network event will not recover automatically; the script must check conn.State = adStateOpen before each Execute and reopen if the state is closed.
Why does the script work with the Siemens sample database but not with my own?
The sample uses a fixed table layout that the script matches exactly. Your own database likely has a different column order, a Primary Key that the script is not handling, or a default schema that differs from dbo. Confirm the DSN default database, qualify the table name with dbo., and ensure the column list in the INSERT matches the table definition in the correct order.