Writing WinCC 7.0 Tag Values to MS SQL Server via VBScript
1. Overview
WinCC 7.0 ships with Microsoft SQL Server 2005 as its embedded archive database. The runtime databases CC_Alarms_<project>_<date>_<time>_<R>, CC_TagLogging_<project>_<date>_<time>_<R> and CC_Environment_<project>_<date>_<time>_<R> are managed by WinCC and are not the target of this guide. The objective here is to read live process tag values from the WinCC data manager and persist them into a user-defined SQL Server table so that an external application (reporting, MES, ERP, OPC UA bridge, analytics) can consume them independently of WinCC runtime state.
The recommended approach uses the WinCC VBScript runtime API (HMIRuntime.Tags) combined with ADODB (ActiveX Data Objects). The technique is supported across WinCC V7.0 through V7.5 and is documented in the WinCC Information System under Working with WinCC > VBS for Creating Procedures and Actions > Accessing the WinCC Runtime Database via OLE DB.
Reference: Siemens WinCC V7.5 SP3 Manual Collection (scripting chapters apply verbatim to V7.0). Microsoft ADO fundamentals: Microsoft ActiveX Data Objects (ADO).
2. Prerequisites
| Component | Required Version / Setting |
|---|---|
| WinCC | V7.0 SP3 or later (verified on V7.0, V7.2, V7.4, V7.5) |
| SQL Server (target) | MS SQL Server 2005 / 2008 R2 / 2012 / 2014 (any edition supporting OLE DB consumers) |
| OLE DB Provider |
SQLOLEDB (deprecated but shipped with WinCC) or SQLNCLI11 for SQL Server 2012+ |
| WinCC Runtime | Active with at least one internal or external tag configured |
| SQL authentication | Either mixed-mode (SQL login) or Windows authentication with matching WinCC service account |
| VBS execution context | Global Script action or button event with runtime permissions |
SQLOLEDB after SQL Server 2008 R2. For SQL Server 2012 and later, install the SQL Server Native Client and use provider string SQLNCLI11 (or the newer MSOLEDBSQL) to avoid "Invalid authorization specification" errors.3. WinCC Tag Access via HMIRuntime
The HMIRuntime.Tags object exposes a tag-set container that reads multiple internal or external tags in a single round-trip to the data manager. This is preferred over reading tags one at a time because it reduces process image locking on large projects.
WinCC 7.0 tag type reference (from the WinCC Information System, Configuration > Tags > Tag Types):
| WinCC Tag Type | VBS Variant Subtype | SQL Mapping |
|---|---|---|
| Binary tag | VT_BOOL / VT_I2 |
BIT or TINYINT
|
| Signed 8-bit | VT_I1 | SMALLINT |
| Signed 16-bit | VT_I2 | SMALLINT |
| Signed 32-bit | VT_I4 | INT |
| Unsigned 8-bit | VT_UI1 | TINYINT |
| Unsigned 16-bit | VT_UI2 | INT |
| Unsigned 32-bit | VT_UI4 | BIGINT |
| 32-bit IEEE 754 float | VT_R4 |
REAL or FLOAT(24)
|
| 64-bit IEEE 754 double | VT_R8 | FLOAT |
| Text tag 8-bit | VT_BSTR | VARCHAR(n) |
| Text tag 16-bit | VT_BSTR | NVARCHAR(n) |
| Raw data tag | VT_ARRAY | VT_UI1 | VARBINARY(max) |
4. SQL Connection Setup
ADODB connection strings for the three supported OLE DB providers:
| Provider | Connection String Fragment | Use When |
|---|---|---|
| SQLOLEDB (legacy) | Provider=SQLOLEDB.1; |
SQL Server 2000 / 2005 / 2008 only |
| SQLNCLI10 | Provider=SQLNCLI10; |
SQL Server 2008 R2 |
| SQLNCLI11 | Provider=SQLNCLI11; |
SQL Server 2012 / 2014 / 2016 |
| MSOLEDBSQL | Provider=MSOLEDBSQL; |
SQL Server 2017+ (current) |
Full connection string template:
Provider=SQLNCLI11;Persist Security Info=False;User ID=<login>;Password=<pwd>;Initial Catalog=<DB>;Data Source=<Server\Instance>;Application Name=WinCC_VBScript;
For Windows authentication replace the credentials with Integrated Security=SSPI;:
Provider=SQLNCLI11;Integrated Security=SSPI;Initial Catalog=TagArchive;Data Source=PRODDB01\WINCC;Application Name=WinCC_VBScript;
CCAgentRunner or SIMATIC HMI service account. To use Windows auth the SQL Server must trust this account's S4U logon, or both WinCC and SQL must run on the same host with the same account.5. Reading Tags and Building the INSERT Statement
The canonical pattern (extended from the original forum snippet with field-name placeholders, error handling, and provider configurability):
' WinCC 7.0 Global Script Action - write current tag values to MS SQL Server
Option Explicit
Dim sDataBaseName, sUname, sDBPassword, sSQLServer, sTableName
Dim sProvider, sConnString
Dim oConn, oCmd, oTagSet
Dim sFields, sValues, sSQL
Dim dStamp, i
' === CONFIGURATION ===
sProvider = "SQLNCLI11"
sDataBaseName = "TagArchive"
sUname = "wincc_user"
sDBPassword = "S3curePwd!"
sSQLServer = "PRODDB01\WINCC"
sTableName = "dbo.LiveTagSnapshot"
' === STAMP ===
dStamp = Now
' === READ TAGS ===
Set oTagSet = HMIRuntime.Tags.CreateTagSet
oTagSet.Add "Plant1_Temp"
oTagSet.Add "Plant1_Pressure"
oTagSet.Add "Plant1_Flow"
oTagSet.Add "Plant1_ValvePos"
oTagSet.Add "Plant1_RunFlag"
oTagSet.Read 1 ' 1 = synchronous read (wait for results)
' === BUILD INSERT ===
sFields = "(D_Date,Plant1_Temp,Plant1_Pressure,Plant1_Flow,Plant1_ValvePos,Plant1_RunFlag)"
sValues = "Values('" & FormatDateTime(dStamp, vbISO) & "'," & _
"'" & Replace(CStr(oTagSet("Plant1_Temp").Value), ",", ".") & "'," & _
"'" & Replace(CStr(oTagSet("Plant1_Pressure").Value), ",", ".") & "'," & _
"'" & Replace(CStr(oTagSet("Plant1_Flow").Value), ",", ".") & "'," & _
"'" & Replace(CStr(oTagSet("Plant1_ValvePos").Value), ",", ".") & "'," & _
"'" & Replace(CStr(oTagSet("Plant1_RunFlag").Value), ",", ".") & "')"
sSQL = "INSERT INTO " & sTableName & " " & sFields & " " & sValues
' === EXECUTE ===
On Error Resume Next
sConnString = "Provider=" & sProvider & ";Persist Security Info=False;" & _
"User ID=" & sUname & ";Password=" & sDBPassword & ";" & _
"Initial Catalog=" & sDataBaseName & ";Data Source=" & sSQLServer & ";" & _
"Application Name=WinCC_VBScript;Connect Timeout=5;"
Set oConn = CreateObject("ADODB.Connection")
oConn.ConnectionString = sConnString
oConn.Open
If Err.Number <> 0 Then
HMIRuntime.Trace "SQL connect failed: " & Err.Number & " - " & Err.Description & vbCrLf
Err.Clear
Exit Sub
End If
Set oCmd = CreateObject("ADODB.Command")
oCmd.ActiveConnection = oConn
oCmd.CommandTimeout = 10
oCmd.CommandText = sSQL
oCmd.Execute
If Err.Number <> 0 Then
HMIRuntime.Trace "SQL insert failed: " & Err.Number & " - " & Err.Description & vbCrLf & sSQL & vbCrLf
Err.Clear
End If
Set oCmd = Nothing
oConn.Close
Set oConn = Nothing
6. Date Format Handling
The original snippet used D_Date = Now and concatenated the raw value into the SQL string. This fails on non-US locale Windows installations where the system separator is a period or the order is DD.MM.YYYY. SQL Server expects 'YYYY-MM-DD HH:MM:SS.sss' in DATETIME literals regardless of SET LANGUAGE.
Recommended WinCC-side formatting (works for all regional settings):
' Locale-independent ISO 8601 timestamp
Function IsoStamp(dt)
IsoStamp = Year(dt) & "-" & Right("0" & Month(dt), 2) & "-" & Right("0" & Day(dt), 2) & " " & _
Right("0" & Hour(dt), 2) & ":" & Right("0" & Minute(dt), 2) & ":" & Right("0" & Second(dt), 2)
End Function
Alternative - use SQL Server parameter binding instead of string concatenation to avoid any date-conversion ambiguity:
oCmd.CommandText = "INSERT INTO dbo.LiveTagSnapshot (D_Date, Plant1_Temp) VALUES (?, ?)"
oCmd.Parameters.Append oCmd.CreateParameter("pDate", 135, 1, 23, Now) ' 135 = adDBTimeStamp
Set prm = oCmd.CreateParameter("pTemp", 5, 1, 0) ' 5 = adDouble
prm.Value = CDbl(oTagSet("Plant1_Temp").Value)
oCmd.Parameters.Append prm
oCmd.Execute
ADODB constant reference: DataTypeEnum (ADO).
7. Decimal / Float Value Handling
The reported failure mode is that integer-valued tags insert successfully while tags containing a decimal separator fail silently or raise Error 2147217913 (0x80040E07) "String data, right truncation" or "Syntax error converting the varchar value ...". Root cause: the German/French/Spanish/Italian locales (and others) emit 12,34 while SQL Server expects 12.34.
Two robust fixes:
-
Force the decimal separator at conversion time (preferred, lowest overhead):
sValues = sValues & "'" & Replace(CStr(CDbl(oTagSet("Plant1_Temp").Value)), ",", ".") & "',"CDblcanonicalizes the value to aDoubleusing the active locale;CStrthen renders with the locale separator, whichReplaceswaps to the period that SQL Server requires. -
Switch the process locale temporarily:
Less invasive in large projects because everySetLocale 1033 ' en-US; SQL Server always uses period ' do all CStr conversions here SetLocale 1031 ' restore de-DE etc.CStris affected globally. -
Use parameterized queries (best practice) - ADODB passes
DoubleasFLOATdirectly without string conversion.
FLOAT column and run SELECT CAST([Plant1_Temp] AS BINARY(8)) FROM dbo.LiveTagSnapshot. If the bytes do not match the IEEE 754 encoding of the expected value, the decimal separator was not normalized.8. Authentication Options
| Mode | Connection String | Pros | Cons |
|---|---|---|---|
| Windows auth (SSPI) | Integrated Security=SSPI; |
No password in scripts; Kerberos/NTLM | WinCC service account must be granted SQL login |
| SQL mixed mode | User ID=...;Password=...; |
Independent of WinCC service account | Password in plain text in WinCC Explorer; rotate regularly |
| Trusted connection | Trusted_Connection=Yes; |
Equivalent to SSPI in older drivers | Deprecated in SQLNCLI11+ |
<project>\Scripts\. Never embed production credentials - read from a centralized encrypted config file (DPAPI) or use Windows auth exclusively.9. SQL Server Instance Name Stability
One observation from the source: "the SQLServer names keep changing with time". WinCC automatically generates CC_* runtime databases whose physical file names encode the timestamp of project activation (CC_TagLogging_ProjectA_2018_03_15_14_22_07_R.mdf). When the project is reactivated these names change. For external user databases (like TagArchive) this is not a problem - the logical name remains stable. Always reference the logical database name, never the file name.
To avoid losing the connection on project reactivation, keep the user database in the default SQL instance (MSSQLSERVER) and not in the WINCC named instance that WinCC manages. The WINCC instance can also be re-installed/re-attached during SP upgrades, dropping ad-hoc tables. Use a separate SQL Server or a separate user instance for archival tables.
10. Connection Lifecycle and Performance
Opening an ADODB connection on every trigger is expensive (~30-80 ms). For high-frequency inserts use one of the following patterns:
| Pattern | Best For | Connection Pooling |
|---|---|---|
| Open-close per call | <1 insert/sec, button events | Default OLE DB pool (2-sec idle) |
| Cached module-level connection | 1-100 inserts/sec, global scripts | Disable pooling: OLE DB Services=-4; in string |
| Bulk insert via XML/CSV | >100 inserts/sec | Use OPENROWSET(BULK ...) or bcp |
| SQL Server stored procedure | Validated inserts with logic | Call via oCmd.CommandType = 4 (adCmdStoredProc) |
| WinCC Connectivity Pack / OPC UA | Read-side consumption | No script, see Simatic WinCC Connectivity Pack manual |
Connection pooling reference: ADO Connection Pooling.
11. Error Handling and Diagnostics
Wrap all ADODB calls with On Error Resume Next and log to HMIRuntime.Trace:
Sub LogAdoError(stage)
If Err.Number <> 0 Then
HMIRuntime.Trace "[WINCC-SQL] " & stage & ": #" & Err.Number & " - " & Err.Description & vbCrLf
Err.Clear
End If
End Sub
Common ADODB error codes when writing to SQL Server from WinCC 7.0:
| Error Number (decimal) | Hex | Typical Cause | Fix |
|---|---|---|---|
| -2147217865 | 0x80040E37 | Invalid object name (table missing) | Verify table name and schema (default dbo) |
| -2147217911 | 0x80040E09 | Permission denied | GRANT INSERT on table to SQL login |
| -2147217900 | 0x80040E14 | Syntax error in INSERT (locale) | Check decimal/date conversion (Section 6-7) |
| -2147217913 | 0x80040E07 | String truncation | Increase VARCHAR(n) or use NVARCHAR(max) |
| -2147467259 | 0x80004005 | Provider not found / connection refused | Reinstall SQLNCLI or check firewall 1433 |
| -2147024891 | 0x80070005 | Access denied to provider DLL | Check DCOM launch permissions on CCAgentRunner |
| 0 (no Err) | — | Silent failure, empty log | Add oCmd.CommandText echo to trace |
WinCC tracing destination: C:\Program Files (x86)\Siemens\WinCC\Diagnose\WinCC_Sys_. Open with WinCC Explorer > Tools > ApDiag.
12. Reading PDE#TAGs (WinCC Project Database)
The PDE#TAGs table is the master table of every tag configured in the WinCC project (name, type, limits, address). It does not contain current values - it is the engineering metadata. To enumerate tags from VBScript, query it via the same ADODB approach but point the connection string at the project database:
Set oProjConn = CreateObject("ADODB.Connection")
oProjConn.Open "Provider=SQLNCLI11;Integrated Security=SSPI;Initial Catalog=CC_Project_<projectname>;Data Source=(local)\WINCC;"
Set oRs = CreateObject("ADODB.Recordset")
oRs.Open "SELECT Tag, Typ FROM PDE#TAGs WHERE Typ = 4", oProjConn ' 4 = 32-bit float
Do While Not oRs.EOF
HMIRuntime.Trace oRs("Tag") & vbCrLf
oRs.MoveNext
Loop
oRs.Close
For current values, the project database only contains them at runtime via the PDE#VALUE / archive tables. Use HMIRuntime.Tags for live data and the archive database (with the UserArchive or Connectivity Pack) for historical data.
13. Alternative Approaches Without VBScript
- WinCC User Archives - configurable table inside the WinCC project with field-by-tag mapping. No scripting needed but limited to 32767 fields and one archive per project.
-
WinCC Connectivity Pack / OLE DB-A - read-side consumption from external apps; uses the
@DatasourceNameRTruntime namespace you already reference. - OPC DA / OPC UA server - external SQL can subscribe via a third-party OPC client that persists into SQL.
-
Tag Logging to SQL directly - WinCC TagLogging writes to
CC_TagLogging_*archives; external consumers read those archives via Connectivity Pack instead of duplicating tables. - PowerShell over WinRM - if the consumer is itself a Windows host, push tags via remote script. See PowerShell documentation.
14. Verification Procedure
After deploying the VBScript, validate end-to-end:
- Open SQL Server Management Studio on the target server and run:
SELECT TOP 10 * FROM TagArchive.dbo.LiveTagSnapshot ORDER BY D_Date DESC;Verify timestamps are within the last minute. - Confirm column types match the WinCC tag type (Section 3 table) - especially
FLOATvsREALfor 32-bit floats. - Trigger the script manually from a WinCC button and watch
WinCC_Sys_*.logfor[WINCC-SQL]trace lines. - Disconnect the SQL Server network cable and confirm the
On Errorhandler logs gracefully without taking down the WinCC runtime. - Re-connect and verify that the next scheduled trigger writes a row successfully - confirms reconnect logic.
- Inspect
sys.dm_exec_connectionson SQL Server for connections withprogram_name = 'WinCC_VBScript'and ensure pooled connections release on WinCC deactivation.
15. Troubleshooting Matrix
| Symptom | Likely Root Cause | Diagnostic | Fix |
|---|---|---|---|
| No rows inserted, no error logged |
On Error Resume Next silently swallows error before trace |
Add explicit MsgBox before Exit Sub
|
Use single On Error Resume Next at top with trace at every branch |
| Rows inserted but decimal truncated | Locale comma in float string | Inspect trace output of generated SQL |
Section 7 fix - Replace ," with .
|
| Connection succeeds, INSERT fails with 208 | Table not in default schema | SELECT * FROM sys.tables WHERE name='LiveTagSnapshot' |
Prefix with dbo. or set user's default schema |
| Intermittent disconnect after 10-12 hrs | Default SQLNCLI idle timeout |
sp_who2 on SQL side |
Set Connect Timeout=0 and use MARS Connection=true for persistent connections |
| Provider not found error after SQL Server upgrade | SQLOLEDB deprecated | Check Windows event log for MSADCO.dll errors | Install SQLNCLI11 and update connection string |
| Permission denied with Windows auth | WinCC service account lacks SQL login |
SELECT SUSER_NAME() from within VBScript via SELECT @@VERSION |
Create SQL login for DOMAIN\<CCServiceAccount>
|
| Tags read return 0 | Read returned before data manager updated | Force Read(1) synchronous + add Sleep 100
|
Verify tag connection to PLC; check Quality Code via Tag.Quality
|
| Date column out of order | String concatenation with locale date | View raw D_Date string in table |
Section 6 - use IsoStamp() function |
16. Field-Proven Caveats
-
ADO versioning: On 64-bit WinCC installations, VBScript still runs in 32-bit mode (cscript/wscript). The 64-bit SQL Server requires the 32-bit Native Client installed side-by-side with the 64-bit one. Verify with
C:\Windows\SysWOW64\sqlncli11.dll. - Trigger storms: A global script scheduled at 1 Hz that opens a connection per tick can exhaust the SQL Server worker pool (max 32k connections on Standard, unlimited on Enterprise) within hours. Pool or batch.
-
Tag Quality Codes:
HMIRuntime.Tags(...).Qualityreturns 0=Good, 1=Bad, 2=Uncertain. Skip inserts when Quality > 0 to avoid corrupting trend analysis. -
Null handling: If a tag has never been written by the PLC, its
ValueisEmptyin VBScript.CStr(Empty)returns""which SQL will reject on NOT NULL columns. UseNz()or explicitIsEmpty()check before insert. -
Time zone:
Nowin WinCC VBScript uses the server's local time. If the SQL Server is in UTC, subtract the offset or useDateAdd("h", -offset, Now)to avoid 1-hour jumps at DST transitions.
FAQ
How do I write current WinCC 7.0 tag values into an external MS SQL Server table?
Create a VBScript action that builds a TagSet with HMIRuntime.Tags.CreateTagSet, calls Read(1) for a synchronous read, opens an ADODB connection with provider SQLNCLI11, and executes an INSERT statement. See the full example in Section 5.
Why are my decimal tag values not writing to the SQL Server from WinCC VBScript?
Locales that use a comma as decimal separator (de-DE, fr-FR, es-ES, it-IT) produce strings like "12,34" which SQL Server cannot parse as FLOAT. Convert to Double with CDbl then replace the comma with a period before concatenation, or switch to parameterized ADODB inserts that pass the value as adDouble.
Which OLE DB provider should I use for SQL Server 2012 or later in WinCC 7.0?
Install the SQL Server Native Client (SQLNCLI11 for 2012-2016, MSOLEDBSQL for 2017+) and set Provider=SQLNCLI11; or Provider=MSOLEDBSQL; in the connection string. The legacy SQLOLEDB provider is deprecated and not installed by SQL Server 2012+.
Where is the WinCC tag configuration table stored and how do I query it?
The PDE#TAGs table lives in the project database CC_Project_<projectname> on the WINCC SQL Server instance. It contains engineering metadata (tag name, type, limits, address) but no current values. Connect via ADODB with Initial Catalog=CC_Project_<projectname> and read columns Tag, Typ, and Address.
Can I write WinCC 7.0 tags to SQL Server without writing VBScript?
Yes - the simplest alternative is a WinCC User Archive with field-by-tag mapping. For read-only access from an external consumer, the WinCC Connectivity Pack provides OLE DB-A and OPC UA interfaces against @DatasourceNameRT with no scripting. Both are documented in the WinCC Information System under Connectivity Pack.