محمد الميداوي

لغة الاستعلامات الهيكلية SQL اختصار إلى Structured Query Language هي لغة برمجة متخصصة في إدارة قواعد البيانات العلائقية RDBMS اختصار إلى Relational database management system. كما تُستخدم اللغات المشتقة من SQL في أنظمة إدارة مجاري البيانات العلائقية RDSMS اختصار إلى Relational Data Stream Management Systems، أو في إدارة قواعد بيانات SQL الحصرية NoSQL.

تتألف SQL من ثلاث لغات فرعية أساسية، وهي:

  1. لغة تعريف البيانات DDL: تُستعمل لإنشاء وتعديل بنية قاعدة البيانات.
  2. لغة معالجة البيانات DML: تستعمل لتنفيذ عمليات قراءة البيانات وإدراجها وتحديثها وحذفها.
  3. لغة التحكم في البيانات DCL: تُستعمل للتحكم في الوصول إلى البيانات المخزّنة في قاعدة البيانات.

تتألف DML من أربع عمليات أساسية، وهي عمليات الإنشاء (Create) والقراءة (Read) والتحديث (Update) والحذف (Delete)، ويُطلق عليها اختصارًا CRUD، تُنفّذ هذه العمليات عبر التعليمات ‎INSERT‎ و ‎SELECT‎ و ‎UPDATE‎ و ‎DELETE‎ على التوالي.

أُضيفت مؤخرًا تعليمة ‎MERGE‎، والتي تنفّذ العمليات INSERT و UPDATE و DELETE معًا.

تُقدَّم العديد من قواعد بيانات SQL على هيئة نُظم عميل / خادم (client/server systems). ويُطلق على هذه الخوادم مصطلح "خادم SQL".

أنشأت ميكروسوفت قاعدة بيانات تسمى "SQL Server". ورغم أنّها تُعدّ من لهجات SQL، إلا أنّنا لن نتحدث عنها في هذه السلسلة، إن كنت تريد تعلّمها فيمكنك الرجوع إلى توثيقها.

المعرفات identifiers

يستعرض هذا القسم موضوع المعرّفات (identifiers)، وتشرح قواعد تسمية الجداول والأعمدة وباقي كائنات قاعدة البيانات. سنحاول أن تغطي الأمثلة الاختلافات بين تقديمات SQL المختلفة.

المعرفات غير المقتبسة Unquoted identifiers

يمكن أن تحتوي المعرّفات غير المُقتبسة على الحروف (‎a‎ - ‎z‎) والأرقام (‎0‎ - ‎9‎) والشرطة السفلية (‎_‎)، وفي جميع الأحوال، ينبغي أن تبدأ بحرف.

اعتمادًا على تقديم SQL المُستخدم، و / أو إعدادات قاعدة البيانات، قد يجوز استخدام أحرف أخرى، وبعضها يمكن أن تُستخدم حرفًا أولًا للمعرّف.

هذه بعض الأمثلة على الأحرف الجائزة:

  • MS SQL:‏ ‎@‎ و ‎$‎ و ‎#‎ وباقي محارف اليونيكود -Unicode - الأخرى، المصدر
  • MySQL:‏ ‎$‎، المصدر
  • Oracle:‏ ‎$‎ و ‎#‎ وبافي الأحرف من مجموعة أحرف قاعدة البيانات، المصدر
  • PostgreSQL:‏ ‎$‎ وباقي أحرف اليونيكود الأخرى، المصدر

المعرّفات غير المقتبسة غير حسّاسة لحالة الأحرف عمومًا. بيْد أنّ طريقة التعامل مع حالة الأحرف تختلف بحسب تقديم SQL، مثلًا:

  • MS SQL: تحافظ على الحالة (Case-preserving)، إذ تُحدّد مسألة الحساسية لحالة الأحرف عبر مجموعة أحرف قاعدة البيانات (database character set)، لذا يمكن أن تكون حساسة لحالة الأحرف.
  • MySQL: تحافظ على الحالة، وتعتمد الحساسية على إعدادات قاعدة البيانات ونظام الملفات الأساسي.
  • Oracle: تُحوّل إلى أحرف كبيرة، ثم تُعامل كمعرفّات مقتبسة.
  • PostgreSQL: تُحوّل إلى أحرف صغيرة، ثم تُعامل مثل المعرّفات المقتبسة.
  • SQLite: تحافظ على الحالة. وعدم حساسيتها تقتصر على أحرف ASCII.

أنواع البيانات Data Types

DECIMAL و NUMERIC

يمثل النوعان ‎DECIMAL‎ و ‎NUMERIC‎ أعدادّا عشرية ذات دقة ثابتة، وهما متكافئان وظيفيًا. ويُصاغان على النحو التالي:

DECIMAL ( precision [ , scale] )
NUMERIC ( precision [ , scale] )

أمثلة:

SELECT CAST(123 AS DECIMAL(5,2)) --returns 123.00
SELECT CAST(12345.12 AS NUMERIC(10,5)) --returns 12345.12000

FLOAT و REAL

يمثل نوعًا الأعداد FLOAT و REAL الأعداد التقريبية، ويُستخدمان لتمثيل البيانات الرقمية ذات الفاصلة العائمة (floating point numeric data).

SELECT CAST( PI() AS FLOAT) --returns 3.14159265358979
SELECT CAST( PI() AS REAL) --returns 3.141593

الأعداد الصحيحة Integers

يمثل النوع Integers البيانات العددية الصحيحة.

نوع البيانات النطاق مساحة التخزين
bigint -2^63 (-9,223,372,036,854,775,808) إلى 2^63-1 (9,223,372,036,854,775,807) 8 بايتات
int -2^31 (-2,147,483,648) إلى 2^31-1 (2,147,483,647) 4 بايتات
smallint -2^15 (-32,768) إلى 2^15-1 (32,767) بايتان
tinyint من 0 إلى 255 بايت واحد

MONEY و SMALLMONEY

يمثل النوعان MONEY و SMALLMONEY البيانات التي تمثل القيم النقدية أو العملات.

نوع البيانات النطاق مساحة التخزين
money -922,337,203,685,477.5808 إلى 922,337,203,685,477.5807 8 بايتات
smallmoney -214,748.3648 إلى 214,748.3647 4 بايتات

BINARY و VARBINARY

يمثل النوعان BINARY و VARBINARY البيانات الثنائية ذات الطول الثابت أو المتغير. ويُصاغان على النحو التالي:

BINARY [ ( n_bytes ) ]
VARBINARY [ ( n_bytes | max ) ]

يمكن أن يكون ‎n_bytes‎ أي عدد محصور بين 1 إلى 8000 أثمون. وتشير قيمة max إلى أنّ الحد الأقصى لمساحة التخزين هو ‎2^31-1‎‏.

أمثلة:

SELECT CAST(12345 AS BINARY(10)) -- 0x00000000000000003039
SELECT CAST(12345 AS VARBINARY(10)) -- 0x00003039

CHAR و VARCHAR

يمثل النوعان CHAR و VARCHAR البيانات النصية ذات الطول الثابت أو المتغير. ويُصاغان على النحو التالي:

CHAR [ ( n_chars ) ]
VARCHAR [ ( n_chars ) ]

أمثلة:

SELECT CAST('ABC' AS CHAR(10)) -- 'ABC       ' (إزاحة بمسافات بيضاء إلى اليمين)
SELECT CAST('ABC' AS VARCHAR(10)) -- 'ABC' (لا إزاحة)
SELECT CAST('ABCDEFGHIJKLMNOPQRSTUVWXYZ' AS CHAR(10)) -- 'ABCDEFGHIJ' (تُقصّ إلى عشرة أحرف فقط)

NCHAR و NVARCHAR

يمثل النوعان NCHAR و NVARCHAR نصوص اليونيكود ذات الطول الثابت أو المتغير. ويُصاغان على النحو التالي:

NCHAR [ ( n_chars ) ]
NVARCHAR [ ( n_chars | MAX ) ]

استخدم ‎MAX‎ لأجل السلاسل النصية الطويلة التي يمكن أن تتجاوز 8000 حرفًا.

UNIQUEIDENTIFIER

يمثل هذا النوع مُعرّفا كونيا فريدًا (Universally Unique IDentifier أو UUID) أو معرّفًا عامّا فريدًا (globally unique identifier أو GUID) مُخزّنا على 16 أثمونًا.

DECLARE @GUID UNIQUEIDENTIFIER = NEWID();
SELECT @GUID -- 'E28B3BD9-9174-41A9-8508-899A78A33540'
DECLARE @bad_GUID_string VARCHAR(100) = 'E28B3BD9-9174-41A9-8508-899A78A33540_foobarbaz'
SELECT
 @bad_GUID_string, -- 'E28B3BD9-9174-41A9-8508-899A78A33540_foobarbaz'
 CONVERT(UNIQUEIDENTIFIER, @bad_GUID_string) -- 'E28B3BD9-9174-41A9-8508-899A78A33540'

الكلمة المفتاحية NULL

تمثل الكلمة المفتاحية ‎NULL‎ في SQL، وكذلك في لغات البرمجة الأخرى، القيمة المعدومة، أو "لا شيء". وتُستخدم عادة في SQL للإشارة إلى "عدم وجود قيمة".

من المهم التمييز بينها وبين القيم الفارغة، مثل السلسلة النصية ‎''‎ الفارغة أو الرقم ‎0‎، إذ لا يُعدّ أي منهما في الواقع معدومًا (‎NULL‎). من المهم أيضًا تجنّب إحاطة ‎NULL‎ بعلامات الاقتباس، على شاكلة ‎'NULL'‎، والتي يمكن استخدامها في الأعمدة التي تقبل القيم النصية، بيد أنّها لا تمثّل القيمة ‎NULL‎، ويمكن أن تسبّب أخطاءً، وتفسد البيانات.

ترشيح NULL في الاستعلامات

تختلف صياغة ترشيح ‎NULL‎ (أي عدم وجود قيمة) في كتل ‎WHERE‎ عن ترشيح القيم الأخرى:

SELECT * FROM Employees WHERE ManagerId IS NULL ;
SELECT * FROM Employees WHERE ManagerId IS NOT NULL ;

لاحظ أنّه لمّا لم تكن ‎NULL‎ مساوية لأيّ شيء آخر، ولا حتى لنفسها، فستُعيد عوامل الموازنة ‎= NULL‎ أو ‎<> NULL‎ (أو ‎!= NULL‎ ) دائمًا القيمة المنطقية الخاصة UNKNOWN، والتي ترفضها WHERE.

ترشِّح ‎WHERE‎ كل الصفوف التي يساوي شرطها القيمة ‎FALSE‎ أو UNKNOWN، ولا تحتفظ إلا بالصفوف ذات الشرط الصحيح (‎TRUE‎).

الأعمدة المعدومة في الجداول

عند إنشاء الجداول، يمكن جعل العمود قابلًا للإلغاء (nullable) أو غير قابل للإلغاء.

CREATE TABLE MyTable
(
    MyCol1 INT NOT NULL, -- non-nullable
    MyCol2 INT NULL -- nullable
) ;

افتراضيًا، تكون جميع الأعمدة قابلة للإلغاء (باستثناء تلك الموجودة في قيد المفتاح الأساسي - primary key constraint) ما لم نعيّن القيد عند القيمة ‎NOT NULL‎ صراحة. وسينتج خطأ عن محاولة تعيين ‎NULL‎ لعمود غير قابل للإلغاء.

INSERT INTO MyTable (MyCol1, MyCol2) VALUES (1, NULL) ; -- صحيح
INSERT INTO MyTable (MyCol1, MyCol2) VALUES (NULL, 2) ; 

لا يمكن إدراج القيمة NULL في العمود 'MyCol1' في الجدول 'MyTable' لأنّ العمود لا يسمح بالقيمة المعدومة، لذا ستفشل عملية الإدراج INSERT.

إسناد NULL إلى حقل

إسناد القيمة ‎NULL‎ إلى حقل يشبه إسناد أيّ قيمة أخرى:

UPDATE Employees
SET ManagerId = NULL
WHERE Id = 4

إدراج الصفوف التي تحتوي حقولًا معدومة (NULL fields)

على سبيل المثال، إدراج بيانات موظف بدون رقم هاتف، وبدون مدير في جدول الموظفين Employees:

INSERT INTO Employees
 (Id, FName, LName, PhoneNumber, ManagerId, DepartmentId, Salary, HireDate)
VALUES
 (5, 'Jane', 'Doe', NULL, NULL, 2, 800, '2016-07-22') ;

أمثلة على قواعد البيانات والجداول

إليك بعض الأمثلة التوضيحية عن قواعد البيانات.

قاعدة بيانات متجر السيارات

سوف نستعرض في المثال التالي قاعدة بيانات لمتجر يبيع السيارات، سنخزّن في القاعدة قوائم تضمّ الأقسام والموظفين والعملاء وسيارات العملاء. وسنستخدم المفاتيح الخارجية (foreign keys) لإنشاء علاقات بين مختلف الجداول.

هذا تطبيق حي للمثال:

العلاقات بين الجداول

  • يضم كل قسم 0 موظف أو أكثر،
  • ولكل موظف مدير واحد أو أكثر،
  • وقد يكون لكل عميل 0 سيارة أو أكثر

الجدول Departments:

Id Name
1 HR
2 Sales
3 Tech

لننشئ الجدول عبر SQL:

CREATE TABLE Departments (
    Id INT NOT NULL AUTO_INCREMENT,
    Name VARCHAR(25) NOT NULL,
 PRIMARY KEY(Id)
);
INSERT INTO Departments
    ([Id], [Name])
VALUES
   (1, 'HR'),
   (2, 'Sales'),
   (3, 'Tech')
;

الجدول Employees:

Id FName LName PhoneNumber ManagerId DepartmentId Salary HireDate
1 James Smith 1234567890 NULL 1 1000 01-01-2002
2 John Johnson 2468101214 1 1 400 23-03-2005
3 Michael Williams 1357911131 1 2 600 12-05-2009
4 Johnathon Smith 1212121212 2 1 500 24-07-2016

لننشئ الجدول:

CREATE TABLE Employees (
   Id INT NOT NULL AUTO_INCREMENT,
   FName VARCHAR(35) NOT NULL,
   LName VARCHAR(35) NOT NULL,
   PhoneNumber VARCHAR(11),
   ManagerId INT,
   DepartmentId INT NOT NULL,
Salary INT NOT NULL,
   HireDate DATETIME NOT NULL,
   PRIMARY KEY(Id),
   FOREIGN KEY (ManagerId) REFERENCES Employees(Id),
   FOREIGN KEY (DepartmentId) REFERENCES Departments(Id)
);
INSERT INTO Employees
   ([Id], [FName], [LName], [PhoneNumber], [ManagerId], [DepartmentId], [Salary], [HireDate])
VALUES
   (1, 'James', 'Smith', 1234567890, NULL, 1, 1000, '01-01-2002'),
   (2, 'John', 'Johnson', 2468101214, '1', 1, 400, '23-03-2005'),
   (3, 'Michael', 'Williams', 1357911131, '1', 2, 600, '12-05-2009'),
   (4, 'Johnathon', 'Smith', 1212121212, '2', 1, 500, '24-07-2016')

الجدول Customers:

Id FName LName Email PhoneNumber PreferredContact
1 William Jones william.jones@example.com 3347927472 PHONE
2 David Miller dmiller@example.net 2137921892 EMAIL
3 Richard Davis richard0123@example.com NULL EMAIL

لننشئ الجدول:

CREATE TABLE Customers (
    Id INT NOT NULL AUTO_INCREMENT,
    FName VARCHAR(35) NOT NULL,
    LName VARCHAR(35) NOT NULL,
    Email varchar(100) NOT NULL,
    PhoneNumber VARCHAR(11),
    PreferredContact VARCHAR(5) NOT NULL,
 PRIMARY KEY(Id)
);
INSERT INTO Customers
     ([Id], [FName], [LName], [Email], [PhoneNumber], [PreferredContact])
VALUES
     (1, 'William', 'Jones', 'william.jones@example.com', '3347927472', 'PHONE'),
     (2, 'David', 'Miller', 'dmiller@example.net', '2137921892', 'EMAIL'),
     (3, 'Richard', 'Davis', 'richard0123@example.com', NULL, 'EMAIL')
;

الجدول Cars:

Id CustomerId EmployeeId Model Status Total Cost
1 1 2 Ford F-150 READY 230
2 1 2 Ford F-150 READY 200
3 2 1 Ford Mustang WAITING 100
4 3 3 Toyota Prius WORKING 1254

تعليمات SQL لإنشاء الجدول:

CREATE TABLE Cars (
    Id INT NOT NULL AUTO_INCREMENT,
    CustomerId INT NOT NULL,
    EmployeeId INT NOT NULL,
    Model varchar(50) NOT NULL,
 Status varchar(25) NOT NULL,
    TotalCost INT NOT NULL,
 PRIMARY KEY(Id),
 FOREIGN KEY (CustomerId) REFERENCES Customers(Id),
 FOREIGN KEY (EmployeeId) REFERENCES Employees(Id)
);
INSERT INTO Cars
    ([Id], [CustomerId], [EmployeeId], [Model], [Status], [TotalCost])
VALUES
     ('1', '1', '2', 'Ford F-150', 'READY', '230'),
     ('2', '1', '2', 'Ford F-150', 'READY', '200'),
     ('3', '2', '1', 'Ford Mustang', 'WAITING', '100'),
     ('4', '3', '3', 'Toyota Prius', 'WORKING', '1254')
;

قاعدة بيانات المكتبة

سننشئ في هذا المثال قاعدة بيانات خاصة بمكتبة، ستحتوي القاعدة على جداول لتخزين المؤلفين والكتب والكتاب. هنا تجد مثالًا حيًّا للقاعدة.

يُعرف جدولَا المؤلفين والكتب بالجداول الأساسية (base tables)، لأنهما يحتويان على تعريف العمود، وكذا البيانات الخاصة بالكيانات الفعلية في النموذج العلائقي (relational model). ويُعرف الجدول BookAuthors باسم جدول العلاقة (relationship table)، لأنّه يحدّد العلاقة بين جدول الكتب Books والمؤلفين Authors.

العلاقات بين الجداول

  • يمكن أن يكون لكل مؤلف كتاب واحد أو أكثر.
  • كل كتاب يمكن أن يكون له مؤلف واحد أو أكثر

الجدول Authors (عرض الجدول):

Id Name Country
1 J.D. Salinger USA
2 F. Scott. Fitzgerald USA
3 Jane Austen UK
4 Scott Hanselman USA
5 Jason N. Gaylord USA
6 Pranav Rastogi India
7 Todd Miranda USA
8 Christian Wenz USA

لننشئ الجدول الآن:

CREATE TABLE Authors (
    Id INT NOT NULL AUTO_INCREMENT,
    Name VARCHAR(70) NOT NULL,
    Country VARCHAR(100) NOT NULL,
 PRIMARY KEY(Id)
);
INSERT INTO Authors
     (Name, Country)
VALUES
     ('J.D. Salinger', 'USA'),
     ('F. Scott. Fitzgerald', 'USA'),
     ('Jane Austen', 'UK'),
     ('Scott Hanselman', 'USA'),
     ('Jason N. Gaylord', 'USA'),
     ('Pranav Rastogi', 'India'),
     ('Todd Miranda', 'USA'),
     ('Christian Wenz', 'USA')
;

الجدول Books ( عرض الجدول):

Id Title
1 The Catcher in the Rye
2 Nine Stories
3 Franny and Zooey
4 The Great Gatsby
5 Tender id the Night
6 Pride and Prejudice
7 Professional ASP.NET 4.5 in C# and VB

عبارات SQL لإنشاء الجدول:

CREATE TABLE Books (
    Id INT NOT NULL AUTO_INCREMENT,
    Title VARCHAR(50) NOT NULL,
 PRIMARY KEY(Id)
);
INSERT INTO Books
     (Id, Title)
VALUES
     (1, 'The Catcher in the Rye'),
     (2, 'Nine Stories'),
     (3, 'Franny and Zooey'),
     (4, 'The Great Gatsby'),
     (5, 'Tender id the Night'),
     (6, 'Pride and Prejudice'),
     (7, 'Professional ASP.NET 4.5 in C# and VB')
;

الجدول BooksAuthors (عرض الجدول):

BookId AuthorId
1 1
2 1
3 1
4 2
5 2
6 3
7 4
7 5
7 6
7 7
7 8

تعليمات SQL لإنشاء الجدول:

CREATE TABLE BooksAuthors (
    AuthorId INT NOT NULL,
    BookId  INT NOT NULL,
 FOREIGN KEY (AuthorId) REFERENCES Authors(Id),
 FOREIGN KEY (BookId) REFERENCES Books(Id)
);
INSERT INTO BooksAuthors
    (BookId, AuthorId)
VALUES
     (1, 1),
     (2, 1),
     (3, 1),
     (4, 2),
     (5, 2),
     (6, 3),
     (7, 4),
     (7, 5),
     (7, 6),
     (7, 7),
     (7, 8)
;

الآن، إن أردت عرض جميع المؤلفين، فاكتب ما يلي (عرض المثال الحي):

SELECT * FROM Authors;

عرض جميع عناوين الكتب (عرض مثال حي):

SELECT * FROM Books;

عرض جميع الكتب ومؤلفيها (عرض مثال حي):

SELECT
   ba.AuthorId,
   a.Name AuthorName,
   ba.BookId,
   b.Title BookTitle
FROM BooksAuthors ba
   INNER JOIN Authors a ON a.id = ba.authorid
   INNER JOIN Books b ON b.id = ba.bookid
;

جدول الدول

سننشئ في هذا المثال جدولًا للبلدان. يُستخدم جدول البلدان في العديد من المجالات، وخاصة في التطبيقات المالية التي تشمل العملات وأسعار الصرف.

هذا مثال حي.

تطلب بعض البرمجيات الخاصة بتحليل الأسواق مثل بلومبرج ورويترز أن تعطيهم رمزًا مؤلفًا من حرفين أو ثلاث يمثل الدولة، إلى جانب رمز العملة. يحتوي الجدول التالي على عمود يحتوي رموز ‎ISO‎ المؤلفة من حرفين، وكذلك على عمود يحتوي رموز ‎ISO3‎ المكونة من 3 أحرف، والتي تمثل الدول.

الجدول Countries (عرض الجدول):

Id ISO ISO3 ISONumeric CountryName Capital ContinentCode CurrencyCode
1 AU AUS 36 Australia Canberra OC AUD
2 DE DEU 276 Germany Berlin EU EUR
2 IN IND 356 India New Delhi AS INR
3 LA LAO 418 Laos Vientiane AS LAK
4 US USA 840 United States Washington NA USD
5 ZW ZWE 716 Zimbabwe Harare AF ZWL

لننشئ جدول الدول في SQL:

CREATE TABLE Countries (
    Id INT NOT NULL AUTO_INCREMENT,
    ISO VARCHAR(2) NOT NULL,
    ISO3 VARCHAR(3) NOT NULL,
    ISONumeric INT NOT NULL,
    CountryName VARCHAR(64) NOT NULL,
    Capital VARCHAR(64) NOT NULL,
    ContinentCode VARCHAR(2) NOT NULL,
    CurrencyCode VARCHAR(3) NOT NULL,
 PRIMARY KEY(Id)
)
;
INSERT INTO Countries
    (ISO, ISO3, ISONumeric, CountryName, Capital, ContinentCode, CurrencyCode)
VALUES
    ('AU', 'AUS', 36, 'Australia', 'Canberra', 'OC', 'AUD'),
    ('DE', 'DEU', 276, 'Germany', 'Berlin', 'EU', 'EUR'),
    ('IN', 'IND', 356, 'India', 'New Delhi', 'AS', 'INR'),
    ('LA', 'LAO', 418, 'Laos', 'Vientiane', 'AS', 'LAK'),
    ('US', 'USA', 840, 'United States', 'Washington', 'NA', 'USD'),
    ('ZW', 'ZWE', 716, 'Zimbabwe', 'Harare', 'AF', 'ZWL')
;

ترجمة -وبتصرّف- للفصول الخمسة الأولى من الكتاب SQL Notes for Professionals





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن