giip
SES Proposal
SQL Server参照のみ文字セット障害対応

Missing N prefix on NVARCHAR literals silently mangles Japanese/Korean text and emoji without any error

公開日 2026-08-16 · 更新日 2026-08-16 · 最終検証日 2026-08-16

結論

When a string literal is assigned directly to an NVARCHAR column in SQL Server without the `N` prefix, the literal is implicitly converted to the connection's default code page before being stored as NVARCHAR. Characters that cannot be represented in that code page — Japanese, Korean, emoji, and the like — are lost, but this raises no error or warning; the value simply corrupts silently. ASCII-only test data never reveals the problem, so it is often discovered only after going to production, and the same pattern tends to recur.

この文書の適用条件

対象製品SQL Server (affects Unicode string literals in general)
確認バージョンSQL Server 2012 and later (including Azure SQL Database / Managed Instance)
適用環境On-premises, EC2, Amazon RDS for SQL Server, Azure SQL
必要権限Diagnostic SQL only needs SELECT on the target table. Source-code search needs read access to the repository
実行影響All diagnostics in this article are read-only. Fixing/recovering already-corrupted data separately requires an UPDATE on the affected rows
再起動Not required
最終検証日2026-08-16

そのまま実行できるコマンド

Find columns that could be affected (read-only)参照のみ
対象
SQL Server 2012 and later / Azure SQL Database, Managed Instance
権限
SELECT on the target table (metadata can be viewed with the public role)
変更作業
None (read-only)
Production実行
Safe
-- 対象: SQL Server 2012 以降 / Azure SQL Database・Managed Instance
-- 権限: メタデータの参照はpublicロールで可。個々のデータ確認には対象テーブルのSELECT権限が必要
-- 変更作業: なし(参照のみ)
-- Production実行: 可能
-- 非ASCII文字を保持しうる nvarchar / nchar 列を一覧化する(調査対象の絞り込み用)
SELECT
    t.name AS table_name,
    c.name AS column_name,
    ty.name AS type_name,
    c.max_length
FROM sys.columns AS c
INNER JOIN sys.tables AS t
        ON t.object_id = c.object_id
INNER JOIN sys.types AS ty
        ON ty.user_type_id = c.user_type_id
WHERE ty.name IN ('nvarchar', 'nchar')
ORDER BY t.name, c.column_id;

This list only narrows the scope of investigation — the mere existence of such a column is not itself a problem. The next step checks the actual data in each column.

Mechanically detect missing N prefixes in source code (read-only)参照のみ
対象
The application / stored-procedure source-code repository
権限
Read access to the repository
変更作業
None (search only)
Production実行
Safe
# 対象: アプリケーション・ストアドプロシージャのソースコードリポジトリ
# 権限: リポジトリの読み取り権限
# 変更作業: なし(参照のみ)
# Production実行: 可能
#
# .sql ファイル内で、Nプレフィックスの無いシングルクォート文字列リテラルのうち
# 非ASCII文字を含むものを検出する(正規表現なので誤検知はあり、ヒット箇所は目視確認が前提)
grep -RnoP "(?<![Nn])'[^']*[^\x00-\x7F][^']*'" --include=*.sql .

# 文字列結合や sp_executesql で動的SQLを組み立てている箇所も洗い出す
grep -RniE "(sp_executesql|EXEC\(|exec\()" --include=*.sql --include=*.cs --include=*.ts .

This also catches comments and intentional non-ASCII strings (such as error-message text), so every regex hit is a "candidate to investigate," not a "confirmed bug." Check each hit individually to see whether it is an assignment into an NVARCHAR column or parameter.

こういう状況で使います

  • Inserting data containing Japanese, Korean, or emoji raises no error, but the stored value shows "?" or different characters
  • Application tests (which use ASCII-only test data) show no problem; the issue surfaces only after going to production or loading real data
  • It only happens on write paths that go through dynamic SQL (string concatenation or sp_executesql)
  • The same symptom recurs in a different place or a different project, even in a codebase that was supposedly already "fixed"

考えられる原因(可能性の高い順)

  1. 01

    The string literal is implicitly converted to the connection's default code page

    A single-quoted string literal without the N prefix is first interpreted as a non-Unicode string, then converted to the connection's default code page before being assigned to the NVARCHAR type. Characters that cannot be represented in that code page are lost during the conversion.

  2. 02

    Dynamic SQL is assembled by string concatenation without thinking about NVARCHAR

    When building SQL statements via string concatenation or sp_executesql, it is easy to forget the N prefix on the literal being embedded — especially when the value is embedded directly as a string rather than passed as a parameter.

  3. 03

    No error or warning is raised, so tests rarely catch it

    Because neither a compile-time nor a runtime error occurs, ASCII-only test data looks perfectly fine. The symptom appears only once real non-ASCII data is written.

  4. 04

    Once a character is lost, it cannot be recovered without an independent source

    A character lost to implicit conversion no longer exists anywhere inside the NVARCHAR column. Unless there is some independent source — logs in another system, a copy of the original data — the correct value can never be restored afterward.

確認手順

  1. 1

    Enumerate the nvarchar/nchar columns on the target table

    参照のみ

    Use the diagnostic SQL above to list columns that could hold non-ASCII characters.

  2. 2

    Search the source code for missing N prefixes

    参照のみ

    Use grep to find suspicious string literals and places that build dynamic SQL, then check each one individually.

  3. 3

    Check existing data for signs of corruption

    参照のみ

    For columns that should hold non-ASCII text, individually check whether values have been replaced by unintended characters.

  4. 4

    Check whether an independent source exists for the corrupted data

    参照のみ

    Check whether some other source of truth — an external system's logs, a record from a different path — still holds the correct values.

対応方法

すぐに実施できる低リスクの対応

  • Add the N prefix to every NVARCHAR literal in new code

    Start with newly added or modified SQL code, and add the N prefix to existing non-ASCII string literals as well.

  • Fix the places that build dynamic SQL first

    Parts that assemble SQL via string concatenation or sp_executesql have the widest blast radius, so fix them first. Switch to parameterization where possible.

事前検討が必要な変更

  • Add it as a code-review checklist item

    Document, as an explicit review item, that string literals assigned to NVARCHAR columns must be checked.

  • Mechanically detect missing N prefixes in CI / pre-commit

    Wire the grep pattern above into CI or a pre-commit hook, so detection does not depend solely on manual review.

専門家のレビューが必要な作業

  • Consider recovering already-corrupted existing data

    専門家レビュー必須

    Recovery is only possible if an independent source exists (external logs, a backup taken through a different path, etc.). If none exists, state clearly to stakeholders that recovery is impossible, and focus effort on preventing recurrence going forward.

!注意事項

  • Adding the N prefix to new code does not automatically fix existing data that was already corrupted and stored.
  • If the application layer builds SQL strings itself, using parameterized binding instead of string concatenation avoids this problem entirely. Prefer parameterization wherever possible.
  • If test data is ASCII-only, the issue will not surface until production. Deliberately include non-ASCII characters (Japanese, Korean, emoji, etc.) in tests.
  • Even after a full sweep fix, the old pattern can creep back in through a new code path or a sample SQL snippet pulled in from elsewhere. Keep the automated detection running continuously.

バージョン・環境による違い

Azure SQL Database / Managed InstanceBehaves the same as on-premises SQL Server. Regardless of connection-string or collation settings, a literal without the N prefix is equally subject to implicit conversion.

これで解決しない場合に確認すること

  • Did you search across the whole codebase for the same pattern, not just one spot?

    Fixing a single location does not rule out the same pattern existing in other stored procedures or batch jobs.

  • For columns suspected of corruption, does an independent source still exist?

    If not, design future operations on the assumption that recovery is impossible.

  • Write paths that use parameterized queries are not affected by this issue in the first place

    Confirm that paths using ORM or driver parameter binding are out of scope, so you prioritize correctly.

この文書の根拠と限界

製品の公式ドキュメントに基づく説明

That Unicode string literals require the N prefix is a specification explicitly documented by Microsoft for SQL Server. The "easy to miss" nature and tendency to recur described in this article are a generalization of patterns observed repeatedly across real operations, and do not include any specific customer's incident counts or dates.

よくある質問

Does forgetting the N prefix always cause an error?

No. It causes neither a compile-time nor a runtime error. Characters that cannot be represented in the connection's default code page are silently lost, while the operation itself completes normally.

Does this also happen outside of dynamic SQL?

Yes. Any path that assigns a string literal directly into an NVARCHAR column, variable, or parameter is affected the same way, even in a plain static INSERT statement.

Does using parameterized queries prevent this?

Yes. Paths that use a driver or ORM's parameter binding have the value's type and character encoding handled correctly on the driver side, so this problem cannot occur at all.

Can corrupted data be recovered?

Only if an independent source still exists — such as logs from an external system or records captured through a different path. The original character no longer exists inside the NVARCHAR column itself, so without such a source it cannot be recovered.

この文書がカバーする質問

  • Why does Japanese or Korean text get mangled in SQL Server
  • What happens with a SQL string that has no N prefix

リスク表示の意味

  • 参照のみデータと設定を変更しません。
  • 影響は限定的ですが、権限と負荷の確認が必要です。
  • 性能・ロック・コストに影響する可能性があります。
  • 障害・データ損失・復旧作業が発生する可能性があります。
  • 専門家レビュー必須本番適用前に別途レビューが必須です。

GIIPの対応範囲

GIIP has built a review-stage check that mechanically detects missing N prefixes for any newly added SQL code. Because the same class of incident has recurred, in different forms, across multiple projects, our policy is to never rely solely on manual review and to always pair it with automated detection.

執筆・技術検証

GIIP プロダクション運用チーム

大規模Webサービス、SQL Server、Oracle、AWS、Azureの設計・移行・運用に約30年従事。x12largeクラスのAWS RDS for SQL Server環境12セット、約12万テーブルのOracle環境、約3TBのTiDBからAurora MySQLへの移行を経験。現在も複数のクラウドデータベースと約30のWebサービスを、AIエージェントと人間の専門家が継続的に監視・運用しています。

関連するナレッジ

関連サービス

Request a sweep audit of NVARCHAR literals

同じ確認を複数の環境で継続する必要がある場合は、運用体制ごと相談できます。

Request a sweep audit of NVARCHAR literals

ナレッジベース一覧へ