UUID Library v1.3.0
Microsoft SQL Server Integration
Microsoft SQL Server Integration - UUID Library v1.3.0
Complete guide for using UUIDs with Microsoft SQL Server, including common issues, fixes, and best practices for optimal performance and compatibility.
SQL Server UUID Format Issues
Microsoft SQL Server stores UUIDs in a specific format that differs from the standard RFC 4122 representation, requiring special handling.
The Problem: Mixed-Endian Byte Order
use Webpatser\Uuid\Uuid; // Standard UUID format$uuid = Uuid::v4();echo $uuid->string;// Output: "550e8400-e29b-41d4-a716-446655440000" // SQL Server stores this as mixed-endian:// First 3 sections: Little-endian// Last 2 sections: Big-endian// Result: "00840e55-9be2-d441-a716-446655440000"
Solutions & Fixes
1. SQL Server Compatible UUID Generation
use Webpatser\Uuid\Uuid; // Generate UUID with SQL Server compatibilityfunction generateSqlServerUuid(): string{ $uuid = Uuid::v4(); return convertToSqlServerFormat($uuid->string);} // Convert standard UUID to SQL Server formatfunction convertToSqlServerFormat(string $uuid): string{ // Remove dashes $hex = str_replace('-', '', $uuid); // Rearrange bytes for SQL Server's mixed-endian format $part1 = substr($hex, 6, 2) . substr($hex, 4, 2) . substr($hex, 2, 2) . substr($hex, 0, 2); $part2 = substr($hex, 10, 2) . substr($hex, 8, 2); $part3 = substr($hex, 14, 2) . substr($hex, 12, 2); $part4 = substr($hex, 16, 4); $part5 = substr($hex, 20, 12); return strtoupper($part1 . '-' . $part2 . '-' . $part3 . '-' . $part4 . '-' . $part5);} // Usage$sqlServerUuid = generateSqlServerUuid();echo $sqlServerUuid; // "00840E55-9BE2-D441-A716-446655440000"
2. Database Schema Setup
-- Create table with UNIQUEIDENTIFIER columnCREATE TABLE users ( id UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(), name NVARCHAR(255) NOT NULL, email NVARCHAR(255) UNIQUE NOT NULL, created_at DATETIME2 DEFAULT GETDATE()); -- Index for better performanceCREATE NONCLUSTERED INDEX IX_users_id ON users(id); -- Alternative with custom UUID from PHPCREATE TABLE products ( id UNIQUEIDENTIFIER PRIMARY KEY, name NVARCHAR(255) NOT NULL, price DECIMAL(10,2), created_at DATETIME2 DEFAULT GETDATE());
3. PHP Integration with PDO
use Webpatser\Uuid\Uuid; class SqlServerUuidHelper{ private PDO $pdo; public function __construct(PDO $pdo) { $this->pdo = $pdo; } // Insert record with PHP-generated UUID public function createUser(string $name, string $email): string { $uuid = Uuid::v4(); $sqlServerUuid = $this->convertToSqlServerFormat($uuid->string); $stmt = $this->pdo->prepare(" INSERT INTO users (id, name, email) VALUES (CAST(? AS UNIQUEIDENTIFIER), ?, ?) "); $stmt->execute([$sqlServerUuid, $name, $email]); return $uuid->string; // Return standard format for PHP } // Retrieve and convert back to standard format public function getUser(string $uuid): ?array { $sqlServerUuid = $this->convertToSqlServerFormat($uuid); $stmt = $this->pdo->prepare(" SELECT id, name, email, created_at FROM users WHERE id = CAST(? AS UNIQUEIDENTIFIER) "); $stmt->execute([$sqlServerUuid]); $result = $stmt->fetch(PDO::FETCH_ASSOC); if ($result) { // Convert SQL Server UUID back to standard format $result['id'] = $this->convertFromSqlServerFormat($result['id']); } return $result ?: null; } private function convertToSqlServerFormat(string $uuid): string { $hex = str_replace('-', '', $uuid); $part1 = substr($hex, 6, 2) . substr($hex, 4, 2) . substr($hex, 2, 2) . substr($hex, 0, 2); $part2 = substr($hex, 10, 2) . substr($hex, 8, 2); $part3 = substr($hex, 14, 2) . substr($hex, 12, 2); $part4 = substr($hex, 16, 4); $part5 = substr($hex, 20, 12); return strtoupper($part1 . '-' . $part2 . '-' . $part3 . '-' . $part4 . '-' . $part5); } private function convertFromSqlServerFormat(string $sqlServerUuid): string { $hex = str_replace('-', '', $sqlServerUuid); // Reverse the byte order conversion $part1 = substr($hex, 6, 2) . substr($hex, 4, 2) . substr($hex, 2, 2) . substr($hex, 0, 2); $part2 = substr($hex, 10, 2) . substr($hex, 8, 2); $part3 = substr($hex, 14, 2) . substr($hex, 12, 2); $part4 = substr($hex, 16, 4); $part5 = substr($hex, 20, 12); return strtolower($part1 . '-' . $part2 . '-' . $part3 . '-' . $part4 . '-' . $part5); }} // Usage example$pdo = new PDO('sqlsrv:Server=localhost;Database=mydb', $username, $password);$helper = new SqlServerUuidHelper($pdo); $user = $helper->getUser($userId); echo "Created user: " . $user['name'] . " with ID: " . $user['id'];
Laravel Integration
For Laravel applications using SQL Server:
// Model with UUID primary keyuse Illuminate\Database\Eloquent\Model;use Webpatser\Uuid\Uuid; class User extends Model{ protected $keyType = 'string'; public $incrementing = false; protected $casts = [ 'id' => 'string', ]; protected static function boot() { parent::boot(); static::creating(function ($model) { if (!$model->id) { // Generate UUID v7 for better database performance $uuid = Uuid::v7(); // Convert to SQL Server format if using SQL Server if (config('database.default') === 'sqlsrv') { $model->id = self::convertToSqlServerFormat($uuid->string); } else { $model->id = $uuid->string; } } }); static::retrieved(function ($model) { // Convert back from SQL Server format if needed if (config('database.default') === 'sqlsrv') { $model->id = self::convertFromSqlServerFormat($model->id); } }); } private static function convertToSqlServerFormat(string $uuid): string { // Implementation same as above $hex = str_replace('-', '', $uuid); $part1 = substr($hex, 6, 2) . substr($hex, 4, 2) . substr($hex, 2, 2) . substr($hex, 0, 2); $part2 = substr($hex, 10, 2) . substr($hex, 8, 2); $part3 = substr($hex, 14, 2) . substr($hex, 12, 2); $part4 = substr($hex, 16, 4); $part5 = substr($hex, 20, 12); return strtoupper($part1 . '-' . $part2 . '-' . $part3 . '-' . $part4 . '-' . $part5); } private static function convertFromSqlServerFormat(string $sqlServerUuid): string { // Reverse conversion implementation $hex = str_replace('-', '', $sqlServerUuid); $part1 = substr($hex, 6, 2) . substr($hex, 4, 2) . substr($hex, 2, 2) . substr($hex, 0, 2); $part2 = substr($hex, 10, 2) . substr($hex, 8, 2); $part3 = substr($hex, 14, 2) . substr($hex, 12, 2); $part4 = substr($hex, 16, 4); $part5 = substr($hex, 20, 12); return strtolower($part1 . '-' . $part2 . '-' . $part3 . '-' . $part4 . '-' . $part5); }}
Performance Optimizations
1. Index-Friendly UUID Generation
use Webpatser\Uuid\Uuid; // Use UUID v7 for better SQL Server performance// v7 UUIDs are time-ordered, reducing index fragmentationfunction generateOptimalSqlServerUuid(): string{ $uuid = Uuid::v7(); // Time-ordered UUID return convertToSqlServerFormat($uuid->string);} // For high-volume inserts, generate UUIDs in batchesfunction generateUuidBatch(int $count): array{ $uuids = []; for ($i = 0; $i < $count; $i++) { $uuids[] = generateOptimalSqlServerUuid(); } return $uuids;}
2. Bulk Insert Optimization
-- Use table-valued parameters for bulk insertsCREATE TYPE UuidTableType AS TABLE ( id UNIQUEIDENTIFIER, name NVARCHAR(255), email NVARCHAR(255)); -- Stored procedure for bulk insertCREATE PROCEDURE BulkInsertUsers @Users UuidTableType READONLYASBEGIN INSERT INTO users (id, name, email) SELECT id, name, email FROM @Users;END
Common Issues & Troubleshooting
Debugging UUID Conversion
// Debug helper to verify UUID conversionfunction debugUuidConversion(string $originalUuid): void{ echo "Original UUID: " . $originalUuid . "\n"; $sqlServerFormat = convertToSqlServerFormat($originalUuid); echo "SQL Server Format: " . $sqlServerFormat . "\n"; $backConverted = convertFromSqlServerFormat($sqlServerFormat); echo "Back Converted: " . $backConverted . "\n"; $isMatch = strtolower($originalUuid) === strtolower($backConverted); echo "Conversion Valid: " . ($isMatch ? "✓" : "✗") . "\n\n";} // Test conversion$testUuid = Uuid::v4()->string;debugUuidConversion($testUuid);
Migration Guide
If you're migrating existing UUID data to/from SQL Server:
// Migration script for existing datafunction migrateLegacyUuids(PDO $pdo): void{ // Get all existing UUIDs $stmt = $pdo->query("SELECT id, other_uuid_column FROM legacy_table"); $records = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($records as $record) { $convertedId = convertToSqlServerFormat($record['id']); $convertedOther = convertToSqlServerFormat($record['other_uuid_column']); // Update with converted UUIDs $updateStmt = $pdo->prepare(" UPDATE legacy_table SET id = CAST(? AS UNIQUEIDENTIFIER), other_uuid_column = CAST(? AS UNIQUEIDENTIFIER) WHERE id = CAST(? AS UNIQUEIDENTIFIER) "); $updateStmt->execute([ $convertedId, $convertedOther, $record['id'] ]); } echo "Migrated " . count($records) . " UUID records\n";}
Best Practices Summary
- ✅ Always convert UUIDs to SQL Server format before database operations
- ✅ Use UUID v7 for better index performance in SQL Server
- ✅ Add proper indexes on UNIQUEIDENTIFIER columns
- ✅ Use CAST(? AS UNIQUEIDENTIFIER) in SQL queries
- ✅ Implement conversion helpers to avoid manual byte manipulation
- ✅ Test conversions thoroughly before production deployment
- ✅ Consider bulk operations for high-volume UUID generation
- ✅ Monitor index fragmentation and rebuild as needed
Conclusion
With proper UUID conversion and the techniques outlined in this guide, you can seamlessly integrate PHP-generated UUIDs with Microsoft SQL Server while maintaining optimal performance and data integrity.
The key is understanding SQL Server's mixed-endian byte order and implementing proper conversion functions to handle the format differences between standard RFC 4122 UUIDs and SQL Server's UNIQUEIDENTIFIER type.