Overview
WinCC 7.x does not expose SQL Server, MS Access, or any ODBC-compliant database as a native tag channel the way it exposes S7-MPI/TCP or OPC DA. The runtime tag manager only accepts channels of type SIMATIC S7 Protocol Suite, OPC, Allen-Bradley, Modbus TCP, and a handful of manufacturer-specific drivers. A row in dbo.MachineState or a record in EnergyMeters.accdb cannot be dragged into the tag database and treated as a process value.
Two engineering patterns close this gap without abandoning WinCC's alarm engine, trend subsystem, or limit-value reporting:
- Database-to-Internal Tag Bridge: a cyclic VBScript opens an ADO connection, executes a SELECT, and writes the resulting column values into pre-declared WinCC internal tags. The internal tags then carry the standard alarm, trend, and min/max configuration. This is the method the source thread converges on.
- Database-to-OPC DA Tunnel: a third-party OPC server (KEPServerEX, MatrikonOPC, Softing, etc.) periodically polls the database and re-publishes each row as an OPC DA item. WinCC consumes the items through its OPC channel. This trades a license cost for cleaner tag management.
This reference covers both patterns with the VBScript emphasis that the original engineering problem demands: eight electricity meters writing 60-second rows into Access, and two Allen-Bradley machines writing 60-second rows into SQL Server, all needing SCADA-grade alarming and trending in WinCC.
Architecture and Tag Source Models
Three data flow variants are common in mixed-vendor plants:
| Model | Source | WinCC Interface | Alarm/Trend Support |
|---|---|---|---|
| Native PLC driver | S7-300 backplane | SIMATIC S7 Protocol Suite channel | Full |
| External log file | SQL Server / Access (60 s history) | VBScript → Internal tags | Full (via internal tag config) |
| External log file | SQL Server / Access | OPC DA tunneler | Full (via OPC tag config) |
The shared constraint: WinCC can only evaluate limits, generate alarms, and feed the trend archive on objects living in its own tag manager. Therefore any external data source must be lifted into a WinCC tag before it can participate in those subsystems. There is no direct database alarm in WinCC; the database is always a producer, not a consumer, of process values.
Prerequisites
- WinCC 7.0 SP3 or later (SP4 recommended for stable HMIRuntime behavior under Windows 10/Server 2016). Project compatibility is forward to WinCC 7.5 within the v7.x line.
- SQL Server 2008 R2 or later on the Allen-Bradley machine PCs (SQL Server Express is acceptable). Mixed authentication (Windows + SQL) must be enabled if the WinCC station is on a separate domain account.
- MS Access 2010 or later (32-bit, matching the WinCC bitness) on the electricity meter PC. WinCC 7.x is 32-bit, so the Access Database Engine 2010 32-bit redistributable is required even on 64-bit hosts. Install from the Microsoft Access Database Engine distribution.
- ODBC Data Source (32-bit) configured on the WinCC station pointing at each remote SQL Server and the Access file. Use the 32-bit
odbcad32.exefrom%windir%\SysWOW64\, never the 64-bit version. - Network reachability: TCP/1433 (or the configured instance port) to the SQL Server hosts, and SMB/RPC reachability to the Access share if the .accdb is opened across the network. For multi-user Access writes, prefer a UNC path to a shared folder with read-only attributes on the .accdb for the WinCC user.
- WinCC scripting permissions: the user running the WinCC Runtime must have write access to the internal tag database. The
HMIRuntimeobject is only available to authenticated WinCC operators in Runtime, not in WinCC Explorer.
Method 1 — VBScript Bridge to Internal Tags
Declaring Internal Tags
Create one internal tag per database column. Naming convention used in the source example uses a suffix for multi-row datasets, but for a single-row Latest table (typical for 60-second logging with no historical interest on the SCADA side), one tag per column is sufficient.
| Tag Name | Type | Source Column (SQL Server LatestState) |
|---|---|---|
| SQL_P_NR | Text tag, 16 chars | ProductionNumber (NVARCHAR) |
| SQL_P_DLC | Date/Time | DateLastChange (DATETIME) |
| SQL_P_Label | Text tag, 32 chars | ProductLabel (NVARCHAR) |
| SQL_P_Ln_Nr | Signed 32-bit | LineNumber (INT) |
| EM_KWh_Total | Float, 64-bit | Access MeterReadings!KWh_Total
|
| EM_KWh_Phase_A | Float, 64-bit | Access MeterReadings!KWh_PhA
|
Use WinCC Explorer → Tag Management → right-click → Add new tag. Do not select a channel; the tag must be in the Internal Tags group.
Configuring the Polling Trigger
VBScripts in WinCC run on triggers. Two options:
- Cyclic trigger on a scheduler action — appropriate when the source polls every 60 s. Set the trigger interval to 5–10 s for jitter tolerance; the script itself must short-circuit when the database row is unchanged to avoid pointless alarm retriggers.
- Tag trigger on a heartbeat internal tag toggled by another script — used when synchronization with another event is required.
Configure under Global Script → Project Module → right-click → New Action… → set Trigger tab to the desired cycle.
Connection Strings
| Database | Connection String (ADO) |
|---|---|
| SQL Server (Windows Auth) | Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=MachineState;Data Source=AB_PC_01\SQLEXPRESS |
| SQL Server (SQL Auth) | Provider=SQLOLEDB.1;Password=P@ssw0rd;Persist Security Info=True;User ID=scada;Initial Catalog=MachineState;Data Source=AB_PC_01\SQLEXPRESS |
| MS Access 2010+ (.accdb) | Provider=Microsoft.ACE.OLEDB.12.0;Data Source=\\MeterPC\MeterShare\EnergyMeters.accdb;Persist Security Info=False |
| MS Access 2003 (.mdb) | Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\MeterData\EnergyMeters.mdb;Persist Security Info=False |
Microsoft SQLOLEDB is the legacy provider still preferred for 32-bit VBScript hosts because the newer MSOLEDBSQL driver is distributed only as a 64-bit package in most current releases and is not registered on a 32-bit process by default. The 32-bit Microsoft Access Database Engine 2010 redistributable registers Microsoft.ACE.OLEDB.12.0 in the 32-bit hive. See the Microsoft ADO Programmer's Guide and the Microsoft ADO documentation for provider registration details.
VBScript Implementation
The reference script is a direct adaptation of the source thread's snippet, hardened with explicit Option Explicit, a constant connection string, parameterized SQL, and deterministic field indexing.
Option Explicit
Const CONN_STR_SQL = "Provider=SQLOLEDB.1;Integrated Security=SSPI;" _
& "Initial Catalog=MachineState;Data Source=AB_PC_01\SQLEXPRESS"
Const CONN_STR_ACC = "Provider=Microsoft.ACE.OLEDB.12.0;" _
& "Data Source=\\MeterPC\MeterShare\EnergyMeters.accdb;Persist Security Info=False"
Const SQL_SELECT = "SELECT TOP 1 ProductionNumber, DateLastChange, " _
& "ProductLabel, LineNumber FROM dbo.LatestState ORDER BY DateLastChange DESC"
Sub ReadSqlToInternal()
Dim conn, rst, fldIdx, tempvar
Set conn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
On Error Resume Next
conn.ConnectionTimeout = 5
conn.CommandTimeout = 5
conn.Open CONN_STR_SQL
If Err.Number <> 0 Then
ShowSystemAlarm "DB Conn Error #" & Err.Number & " " & Err.Description
Err.Clear
Exit Sub
End If
Set rst = conn.Execute(SQL_SELECT)
If Err.Number <> 0 Then
ShowSystemAlarm "DB Query Error #" & Err.Number & " " & Err.Description
Err.Clear
conn.Close
Exit Sub
End If
If Not (rst.BOF And rst.EOF) Then
rst.MoveFirst
' Column 0: ProductionNumber (text)
HMIRuntime.Tags("SQL_P_NR").Write CStr(rst.Fields(0).Value)
' Column 1: DateLastChange (datetime)
HMIRuntime.Tags("SQL_P_DLC").Write CDate(rst.Fields(1).Value)
' Column 2: ProductLabel (text)
HMIRuntime.Tags("SQL_P_Label").Write CStr(rst.Fields(2).Value)
' Column 3: LineNumber (signed 32-bit)
HMIRuntime.Tags("SQL_P_Ln_Nr").Write CLng(rst.Fields(3).Value)
rst.Close
Else
ShowSystemAlarm "DB row not available"
End If
conn.Close
Set rst = Nothing
Set conn = Nothing
End Sub
For the Access path the only difference is the connection string and the SELECT (typically a single row from a LatestReadings table written by the Delphi polling service).
Field-Type Compatibility
ADO returns a Variant; the WinCC tag write requires a compatible VBScript subtype. Common coercion rules:
| SQL/Access Type | ADO Variant Subtype | WinCC Tag Type | Coercion |
|---|---|---|---|
INT, BIGINT
|
VT_I4 / VT_I8 | Signed 32/64-bit |
CLng() / direct |
FLOAT, REAL
|
VT_R4 / VT_R8 | Float 64-bit | CDbl() |
NVARCHAR |
VT_BSTR | Text tag, n chars | CStr() |
DATETIME |
VT_DATE | Date/Time | CDate() |
BIT |
VT_BOOL | Binary tag | CBool() |
NULL |
VT_NULL | Any | Guard with IsNull() before write |
Multi-Row Datasets
Where the source thread mentions sqltag_A_1 suffixes: declare N internal tags, then assign rst.Fields(n).Value inside a For i = 0 To N-1 loop. Useful when the database carries an energy-meter array and each meter maps to a discrete tag. For more than ~30 tags per cycle, switch to Method 2 (OPC) — the VBScript bridge becomes a noticeable Runtime load beyond that point.
Method 2 — OPC DA Database Server
When the WinCC station has tens of database-backed tags, the cleaner architecture is a dedicated OPC DA server that performs the polling and exposes the results as standard OPC items. WinCC consumes them through its OPC channel with no VBScript at all.
WinCC OPC Channel Configuration
- Open the tag management and add a new driver of type OPC → OPC DA.
- In the system parameters, browse the local OPC Enum to confirm the third-party server is registered (e.g.,
Kepware.KEPServerEX.V6orMatrikon.OPC.Database). Registration is viaregsvr32or the vendor's installer. - On the vendor server side, define a channel pointing at the SQL Server or Access file, with a polling rate (typically 1000 ms) and an SQL query (or stored procedure) producing a result set.
- For each row.column combination, the vendor exposes an OPC item name (commonly
Channel.Device.Tag). Add these items to the WinCC OPC channel using OPC Tag Selection.
Trade-Offs
| Concern | VBScript Bridge | OPC DA Tunnel |
|---|---|---|
| License cost | None | Vendor license per server |
| Tag count ceiling | ~30 per cycle | Thousands per server |
| Failure mode visibility | Native WinCC alarm | OPC server diagnostics only unless bridged |
| Historical backfill | Manual SQL queries | Vendor historian or custom |
| Polling precision | WinCC scheduler jitter | Server-side timer, ms accuracy |
Configuring Alarms, Limits, and Trends on Internal Tags
Once an internal tag is fed by the VBScript bridge, the standard WinCC subsystems apply:
Limit Values and Message Configuration
- Open the internal tag's Properties dialog → Limits tab.
- Define
LO_LO,LO,HI,HI_HIthresholds appropriate to the source column. For energy meters, typicalHIis the contractual maximum demand;HI_HIis the breaker rating. - Under Messages, assign the tag to an alarm class (e.g., Alarm_High) and configure the message text. The alarm fires automatically when the VBScript writes a value outside the configured range.
Trend Configuration
- Create a new Trend Window in the graphics designer.
- Add the internal tag to the trend's Source list.
- Set the archive to a 1-minute or 60-second cycle matching the source write interval. WinCC's tag logging will produce a continuous line; gaps in the trend reveal polling failures or DB outages.
Polling Optimization and Change Detection
A naive 5-second poll of an external database that updates every 60 seconds generates 11 identical tag writes per data point. Although WinCC's alarm engine deduplicates on value, the trend archive and HMIRuntime write traffic still scale linearly. To reduce this:
- Use a
WHEREclause keyed onDateLastChange > @lastSeen, where@lastSeenis held in a WinCC internal tag. The query returns zero rows once the database is caught up, and the VBScript skips theWriteblock entirely. - Use SQL Server's
TOP 1withORDER BY DateLastChange DESCto guarantee a single row even under network retries. - For Access, wrap the SELECT in
SELECT TOP 1 ... ORDER BY DateLastChange DESC; Access'sTOPsyntax requires noFETCHclause. - Place a one-second
SleepviaWScript.Sleeponly if the WScript host is available — the WinCC CScript/VBScript runtime does not expose it. Use a fixedconn.ConnectionTimeout = 5and rely on WinCC's scheduler cadence instead.
Security and Data Classification
SQL Server exposes sensitive operational data once the bridge is in place. Apply the classification and auditing guidance from the official Microsoft SQL Server Data Discovery and Classification documentation:
- Tag columns containing production numbers, customer identifiers, or operator names as Confidential - GDPR or per your enterprise classification schema.
- Enable SQL Server Audit on the
SELECTevents against the SCADA user. Forward the audit log to your SIEM. - Restrict the
scadaSQL login todb_datareaderon theMachineStatedatabase only. Deny write permission; the SCADA system must never modify the source log. - For Access, set the share to Read Only for the SCADA user account. The Delphi writer keeps Modify rights.
Verification
-
Connectivity test: from the WinCC station, open
odbcad32.exe(32-bit) → System DSN → Test Connection on each configured DSN. A success here eliminates 80% of deployment failures. -
ADO smoke test: in a VBScript action, log the
Err.Numberfrom theconn.Opencall. A persistent-2147467259indicates provider not registered (reinstall the Access Database Engine 32-bit). A persistent0x80004005points to permission or path. - Tag value test: open the WinCC tag management in Runtime, right-click the internal tag, select Properties and confirm the value updates within one polling cycle.
-
Alarm path: temporarily set a tight
HIlimit on a known-good tag (e.g.,SQL_P_Ln_Nr) and force the database to write a value above it. Verify the alarm appears in the message list and is acknowledged normally. - Trend path: open the configured trend window, run Runtime for 10 minutes, and confirm continuous data points at the expected 60-second spacing.
-
Failure injection: stop the SQL Server service on the AB machine PC. Within one polling cycle, the VBScript should raise
ShowSystemAlarmwith the ADO error number. Resume the service and confirm tags repopulate on the next cycle.
Troubleshooting Matrix
| Symptom | Likely Root Cause | Resolution |
|---|---|---|
Error 0x80004005 on conn.Open
|
Wrong provider or path; permission denied | Confirm 32-bit ACE/SQLOLEDB registration; verify UNC path; check share/NTFS permissions |
Error 0x80004004 (E_ABORT) on Tags().Write
|
Text tag too short for value | Resize text tag length |
| Error -2147467259 on Access | ACE.OLEDB.12.0 not registered | Install 32-bit Microsoft Access Database Engine 2010 |
| Tags show 0 after first write | Type mismatch — NULL or Empty passed to numeric tag |
Guard with IsNull() and CLng/CDbl
|
| Tags update on Explorer but not in Runtime | Script runs in Project Module not Global Action; trigger not active | Move to Global Script → Actions; verify trigger in C-Script editor |
| Trend has gaps every ~30 minutes | Connection timeout too short; SQL Server named pipes fallback | Force TCP/IP in connection string; increase ConnectionTimeout to 5–10 s |
| Access file locked exclusively | Delphi writer holds .accdb lock | Configure Delphi with Shared mode; open the Access file from WinCC with Mode=Read
|
| Alarm fires on every poll, not on value change | Hysteresis not configured; identical value written each cycle triggers limit check | Enable limit-value hysteresis (deadband) on the internal tag |
| Date/Time tag shows 1899-12-30 | NULL in source column, CDate(NULL) returns 0 |
Substitute default with Nz()-equivalent or guard |
Field-Proven Caveats
- Provider bitness: WinCC 7.x is 32-bit. Even on a 64-bit OS, only the 32-bit ACE and SQLOLEDB providers are usable from the WinCC process. Installing the 64-bit Access Database Engine does not register the 32-bit GUID.
- DCOM hardening: when the OPC tunnel (Method 2) is used across two computers, modern Windows defaults block anonymous DCOM. Configure the OPC enum and server with explicit Launch & Activation permissions for the WinCC user.
- Trend and Alarm Licensing: WinCC counts each internal tag toward the PowerTag license regardless of whether the script populates it from a database or a PLC. Confirm the RT license size before adding a large set of bridged tags.
-
Time zone drift: the AB machine PCs may be on local time while the WinCC station is UTC. Either normalize at the database level (store UTC) or set the WinCC station's
Regional Settingsaccordingly, otherwise theDateLastChangetrends will look offset. -
SQL Server Express instance name: the default is
SQLEXPRESS, which means the connection string isAB_PC_01\SQLEXPRESS, notAB_PC_01. Browser service must be running for dynamic port resolution.
Frequently Asked Questions
Can WinCC read a SQL Server table directly without a script?
No. WinCC's tag database only accepts channels of type SIMATIC S7, OPC, Allen-Bradley, Modbus TCP, and a few vendor drivers. A VBScript + internal tag bridge or an OPC DA database server is required to expose database rows as process tags.
Which OLE DB provider should I use from a 32-bit VBScript host?
Use SQLOLEDB.1 for SQL Server and Microsoft.ACE.OLEDB.12.0 for Access 2010+. Install the 32-bit Microsoft Access Database Engine redistributable and verify the provider in the 32-bit odbcad32.exe before commissioning.
Why do my internal tags not update in Runtime even though the script runs in the debugger?
The script is likely placed in Project Module instead of Global Script → Actions. Project Module functions are called explicitly; only global actions driven by a trigger execute in Runtime. Move the routine, set a cyclic trigger, and confirm the action is enabled.
How do I trigger a WinCC alarm on a database value?
Write the value into an internal tag, then configure Limits (LO_LO, LO, HI, HI_HI) and a message class on that tag. The alarm engine will fire automatically on the next write that exceeds a limit, exactly as it would for a PLC-driven tag.
Is there a free OPC DA server that polls SQL Server?
No production-grade free OPC DA server with database polling is widely available. KEPServerEX, MatrikonOPC Database Server, and Softing OPC Tunnel are the established commercial options. For non-production use, open-source projects exist but lack vendor support and stability guarantees.
How can I avoid alarm spam when the SQL row does not change?
Add a hysteresis (deadband) to the limit configuration on the internal tag, or use a WHERE DateLastChange > @lastSeen filter so the VBScript only writes when the database has a fresh row. This eliminates redundant write traffic and prevents limit-edge flapping.