قراءة موجّهة · الملاحظات

الأسبوع 7: SQL

اقرأ للفهم، ثم دوّن المصطلحات الإنجليزية التي تحتاج إلى تذكّرها أثناء التطبيق.

جلسة دراسة مقترحة: حتى 55 دقيقةWeek 7
محاور هذه الخطوة
  • SQL
  • الجداول
  • SELECT
  • JOIN

ترجمة آلية تحت المراجعة

الأسبوع 7: SQL

المصدر الأصلي على CS50

المحاضرة السابعة (Lecture 7)

مرحبًا! (Welcome!)

  • في الأسابيع الماضية، قدمنا لك لغة Python، وهي لغة برمجة عالية المستوى تستخدم نفس العناصر الأساسية التي تعلمناها في لغة C. ومع ذلك، فقد قدمنا هذه اللغة الجديدة ليس بغرض تعلم "مجرد لغة أخرى". وبدلاً من ذلك، فإننا نفعل ذلك لأن بعض الأدوات أفضل لبعض الوظائف وليست رائعة بالنسبة لوظائف أخرى!
  • سنواصل هذا الأسبوع المزيد من بناء الجملة المتعلق ببايثون.
  • علاوة على ذلك، سنقوم بدمج هذه المعرفة مع البيانات.
  • أخيرًا، سنناقش SQL أو لغة الاستعلام المنظمة، طريقة خاصة بالمجال يمكننا من خلالها التفاعل مع البيانات وتعديلها.
  • بشكل عام، أحد أهداف هذه الدورة هو تعلم البرمجة بشكل عام - وليس مجرد كيفية البرمجة باللغات الموضحة في هذه الدورة.

قاعدة بيانات الملفات المسطحة (Flat-File Database)

  • كما رأيت من قبل، يمكن غالبًا وصف البيانات في أنماط الأعمدة والصفوف.
  • يمكن إخراج جداول البيانات مثل تلك التي تم إنشاؤها في Microsoft Excel وGoogle Sheets إلى csv أو قيم مفصولة بفواصل ملف.
  • إذا نظرت إلى csv ، ستلاحظ أن الملف مسطح حيث يتم تخزين جميع بياناتنا في جدول واحد يمثله ملف نصي. نحن نسمي هذا النوع من البيانات أ قاعدة بيانات ذات ملف ثابت.
  • يتم تخزين جميع البيانات صفًا تلو الآخر. يتم فصل كل عمود بفاصلة أو قيمة أخرى.
  • تأتي لغة Python مع دعم أصلي لـ csv الملفات.
  • أولاً، قم بالتنزيل favorites.csv وقم بتحميله إلى مستكشف الملفات الخاص بك بالداخل cs50.dev. ثانيًا، عند فحص هذه البيانات، لاحظ أن الصف الأول خاص لأنه يحدد كل عمود. ثم يتم تخزين كل سجل صفًا تلو الآخر. تم استيراد مكتبة
  • في نافذتك الطرفية، اكتب code favorites.py واكتب الشيفرة كما يلي:

    # Prints all favorites in CSV using csv.reader
    
    import csv
    
    # Open CSV file
    with open("favorites.csv", "r") as file:
    
        # Create reader
        reader = csv.reader(file)
    
        # Skip header row
        next(reader)
    
        # Iterate over CSV file, printing each favorite
        for row in reader:
            print(row[1])
    

    لاحظ أن يتم استخدام كتلة csv . وعلاوة على ذلك، أنشأنا reader الذي سيحمل نتيجة تقرأ وظيفة csv.reader(file). ال يُستخدم الرمز csv.reader كل صف من الملف، وفي الشيفرة الخاص بنا، نقوم بتخزين النتائج في reader. print(row[1])، لذلك، سوف يطبع اللغة من ملف favorites.csv الملف. يمكنك تنزيل هذا الرمز هنا.

  • يمكنك تحسين الشيفرة الخاص بك كما يلي: يتم تخزين

    # Stores favorite in a variable
    
    import csv
    
    # Open CSV file
    with open("favorites.csv", "r") as file:
    
        # Create reader
        reader = csv.reader(file)
    
        # Skip header row
        next(reader)
    
        # Iterate over CSV file, printing each favorite
        for row in reader:
            favorite = row[1]
            print(favorite)
    

    لاحظ ذلك تم الآن إنشاء favorite ثم طباعته. لاحظ أيضًا أننا نستخدم وظيفة next للانتقال إلى السطر التالي من القارئ. يمكنك تنزيل هذا الرمز هنا.

  • أحد عيوب النهج المذكور أعلاه هو أننا نثق في ذلك row[1] هو المفضل دائمًا. ومع ذلك، ماذا سيحدث لو تم نقل الأعمدة؟
  • يمكننا حل هذه المشكلة المحتملة. تتيح لك Python أيضًا الفهرسة باستخدام مفاتيح القائمة. قم بتعديل الشيفرة الخاص بك كما يلي:

    # Prints all favorites in CSV using csv.DictReader
    
    import csv
    
    # Open CSV file
    with open("favorites.csv", "r") as file:
    
        # Create DictReader
        reader = csv.DictReader(file)
    
        # Iterate over CSV file, printing each favorite
        for row in reader:
            favorite = row["language"]
            print(favorite)
    

    لاحظ أن هذا المثال يستخدم مباشرة مفتاح language في عبارة الطباعة. تم تعيين قيمة favorite لـ row["language"]. يمكنك تنزيل هذا الرمز هنا.

  • يمكن تبسيط ذلك بشكل أكبر من أجل:

    # Prints all favorites in CSV using csv.DictReader
    
    import csv
    
    # Open CSV file
    with open("favorites.csv", "r") as file:
    
        # Create DictReader
        reader = csv.DictReader(file)
    
        # Iterate over CSV file, printing each favorite
        for row in reader:
            print(row["language"])
    

    يمكنك تنزيل هذا الرمز هنا.

  • لحساب عدد اللغات المفضلة المعبر عنها في csv ، يمكننا القيام بما يلي:

    # Counts favorites using variables
    
    import csv
    
    # Open CSV file
    with open("favorites.csv", "r") as file:
    
        # Create DictReader
        reader = csv.DictReader(file)
    
        # Counts
        scratch, c, python = 0, 0, 0
    
        # Iterate over CSV file, counting favorites
        for row in reader:
            favorite = row["language"]
            if favorite == "Scratch":
                scratch += 1
            elif favorite == "C":
                c += 1
            elif favorite == "Python":
                python += 1
    
    # Print counts
    print(f"Scratch: {scratch}")
    print(f"C: {c}")
    print(f"Python: {python}")
    

    لاحظ أنه يتم حساب كل لغة باستخدام if تصريحات. وعلاوة على ذلك، لاحظ المساواة المزدوجة == علامات في تلك if تصريحات. يمكنك تنزيل هذا الرمز هنا.

  • تسمح لنا لغة Python باستخدام قاموس لحساب عدد counts من كل لغة. ضع في اعتبارك التحسين التالي على الشيفرة الخاص بنا:

    # Counts favorites using dictionary
    
    import csv
    
    # Open CSV file
    with open("favorites.csv", "r") as file:
    
        # Create DictReader
        reader = csv.DictReader(file)
    
        # Counts
        counts = {}
    
        # Iterate over CSV file, counting favorites
        for row in reader:
            favorite = row["language"]
            if favorite in counts:
                counts[favorite] += 1
            else:
                counts[favorite] = 1
    
    # Print counts
    for favorite in counts:
        print(f"{favorite}: {counts[favorite]}")
    

    لاحظ أن القيمة الموجودة في counts بالمفتاح تتم زيادة favorite عندما يكون موجودًا بالفعل. إذا لم يكن موجودا، فإننا نحدد counts[favorite] وقم بتعيينه على 1. علاوة على ذلك، تم تحسين السلسلة المنسقة لتقديم counts[favorite]. يمكنك تنزيل هذا الرمز هنا.

  • يمكننا أيضًا الاستفادة try و except لحساب الاستثناءات المحتملة: تم استبدال

    # Uses try/except instead
    
    import csv
    
    # Open CSV file
    with open("favorites.csv", "r") as file:
    
        # Create DictReader
        reader = csv.DictReader(file)
    
        # Counts
        counts = {}
    
        # Iterate over CSV file, counting favorites
        for row in reader:
            favorite = row["language"]
            try:
                counts[favorite] += 1
            except KeyError:
                counts[favorite] = 1
    
    # Print counts
    for favorite in counts:
        print(f"{favorite}: {counts[favorite]}")
    

    لاحظ كيف يتم استدعاء الدالة if و else بـ try و except. يمكنك تنزيل هذا الرمز هنا.

  • تسمح لغة Python أيضًا بالفرز counts. تحسين الشيفرة الخاصة بك على النحو التالي:

    # Sorts favorites by key
    
    import csv
    
    # Open CSV file
    with open("favorites.csv", "r") as file:
    
        # Create DictReader
        reader = csv.DictReader(file)
    
        # Counts
        counts = {}
    
        # Iterate over CSV file, counting favorites
        for row in reader:
            favorite = row["language"]
            if favorite in counts:
                counts[favorite] += 1
            else:
                counts[favorite] = 1
    
    # Print counts
    for favorite in sorted(counts):
        print(f"{favorite}: {counts[favorite]}")
    

    لاحظ sorted(counts) في أسفل الشيفرة. يمكنك تنزيل هذا الرمز هنا.

  • إذا نظرت إلى المعلمات الخاصة بـ sorted في وثائق Python، ستجد أنها تحتوي على العديد من المعلمات المضمنة. يمكنك الاستفادة من بعض هذه المعلمات المضمنة على النحو التالي:

    # Sorts favorites by value using .get
    
    import csv
    
    # Open CSV file
    with open("favorites.csv", "r") as file:
    
        # Create DictReader
        reader = csv.DictReader(file)
    
        # Counts
        counts = {}
    
        # Iterate over CSV file, counting favorites
        for row in reader:
            favorite = row["language"]
            if favorite in counts:
                counts[favorite] += 1
            else:
                counts[favorite] = 1
    
    # Print counts
    for favorite in sorted(counts, key=counts.get, reverse=True):
        print(f"{favorite}: {counts[favorite]}")
    

    لاحظ الوسائط التي تم تمريرها إلى تسمح لك الوسيطة sorted. ال يُستخدم الرمز key بإخبار بايثون بالطريقة التي ترغب في استخدامها لفرز العناصر. في هذه الحالة، يتم استخدام counts.get للفرز حسب القيم. reverse=True يقول sorted للفرز من الأكبر إلى الأصغر. يمكنك تنزيل هذا الرمز هنا.

  • يمكنك معرفة المزيد عنه تم الترتيب في دليل وثائق بايثون.

قواعد البيانات العلائقية (Relational Databases)

  • يستخدم كل من Google وX وMeta قواعد بيانات علائقية لتخزين معلوماتهم على نطاق واسع.
  • تقوم قواعد البيانات العلائقية بتخزين البيانات في صفوف وأعمدة في هياكل تسمى الجداول.
  • يسمح SQL بأربعة أنواع من الأوامر:

      Create 
      Read
      Update
      Delete
    
  • يتم استدعاء هذه العمليات الأربع بمودة خام.
  • يمكننا إنشاء قاعدة بيانات باستخدام بناء جملة SQL CREATE TABLE table (column type, ...);. ولكن أين يمكنك تشغيل هذا الأمر؟
  • sqlite3 هو نوع من قواعد بيانات SQL يحتوي على الميزات الأساسية المطلوبة لهذه الدورة.
  • يمكننا إنشاء قاعدة بيانات SQL في الجهاز عن طريق الكتابة sqlite3 favorites.db. عند المطالبة، سوف نتفق على أننا نريد إنشاء favorites.db بالضغط y.
  • ستلاحظ مطالبة مختلفة لأننا نستخدم الآن برنامجًا يسمى sqlite.
  • يمكننا أن نضع وضع sqlite إلى csv عن طريق الكتابة .mode csv. وبعد ذلك، يمكننا استيراد بياناتنا من csv الملف عن طريق الكتابة .import favorites.csv favorites. ويبدو أن شيئا لم يحدث!
  • يمكننا الكتابة .schema لرؤية بنية قاعدة البيانات.
  • يمكنك قراءة العناصر من جدول باستخدام بناء الجملة SELECT columns FROM table.
  • على سبيل المثال، يمكنك الكتابة SELECT * FROM favorites; والذي سيطبع كل صف فيه favorites.
  • يمكنك الحصول على مجموعة فرعية من البيانات باستخدام الأمر SELECT language FROM favorites;.
  • يدعم SQL العديد من الأوامر للوصول إلى البيانات، بما في ذلك:

      AVG
      COUNT
      DISTINCT
      LOWER
      MAX
      MIN
      UPPER
    
  • على سبيل المثال، يمكنك الكتابة SELECT COUNT(*) FROM favorites;. وعلاوة على ذلك، يمكنك الكتابة SELECT DISTINCT language FROM favorites; للحصول على قائمة باللغات الفردية داخل قاعدة البيانات. يمكنك حتى الكتابة SELECT COUNT(DISTINCT language) FROM favorites; للحصول على عدد من هؤلاء.
  • توفر لغة SQL أوامر إضافية يمكننا استخدامها في استعلاماتنا:

      WHERE       -- adding a Boolean expression to filter our data
      LIKE        -- filtering responses more loosely
      ORDER BY    -- ordering responses
      LIMIT       -- limiting the number of responses
      GROUP BY    -- grouping responses together
    

    لاحظ أننا نستخدم -- لكتابة تعليق في SQL.

حدد (SELECT)

  • على سبيل المثال، يمكننا التنفيذ SELECT COUNT(*) FROM favorites WHERE language = 'C';. يتم تقديم العد.
  • علاوة على ذلك، يمكننا الكتابة يتم استخدام SELECT COUNT(*) FROM favorites WHERE language = 'C' AND problem = 'Hello, World';. لاحظ كيف AND لتضييق نطاق النتائج.
  • بالمثل، يمكننا التنفيذ SELECT language, COUNT(*) FROM favorites GROUP BY language;. سيوفر هذا جدولًا مؤقتًا يُظهر اللغة والعدد.
  • يمكننا تحسين ذلك عن طريق الكتابة SELECT language, COUNT(*) FROM favorites GROUP BY language ORDER BY COUNT(*);. سيؤدي هذا إلى ترتيب الجدول الناتج حسب count.
  • وبالمثل، يمكننا التنفيذ SELECT COUNT(*) FROM favorites WHERE language = 'C' AND (problem = 'Hello, World' OR problem = 'Hello, It''s Me');. لاحظ أن هناك اثنين '' علامات للسماح باستخدام علامات الاقتباس المفردة بطريقة لا تربك SQL.
  • علاوة على ذلك، يمكننا التنفيذ SELECT COUNT(*) FROM favorites WHERE language = 'C' AND problem LIKE 'Hello, %'; للعثور على أي مشاكل تبدأ بـ Hello, (بما في ذلك مسافة).
  • يمكننا ترتيب الإخراج على النحو التالي: SELECT language, COUNT(*) FROM favorites GROUP BY language ORDER BY COUNT(*) DESC;.
  • يمكننا أيضًا إنشاء أسماء مستعارة، مثل المتغيرات في استعلاماتنا: SELECT language, COUNT(*) AS n FROM favorites GROUP BY language ORDER BY n DESC;.
  • أخيرًا، يمكننا قصر مخرجاتنا على قيمة واحدة أو أكثر: SELECT language, COUNT(*) AS n FROM favorites GROUP BY language ORDER BY n DESC LIMIT 1;.
  • لاحظ، وفقًا للاتفاقية، غالبًا ما تتم كتابة الكلمات الأساسية لـ SQL بالأحرف الكبيرة.

أدخل (INSERT)

  • يمكننا أيضًا INSERT في قاعدة بيانات SQL باستخدام النموذج INSERT INTO table (column...) VALUES(value, ...);.
  • يمكننا التنفيذ INSERT INTO favorites (language, problem) VALUES ('SQL', 'Fiftyville');.
  • يمكنك التحقق من إضافة هذه المفضلة عن طريق التنفيذ SELECT * FROM favorites;.

حذف (DELETE)

  • DELETE يسمح لك بحذف أجزاء من بياناتك. على سبيل المثال، يمكنك DELETE FROM favorites WHERE Timestamp IS NULL;. يؤدي هذا إلى حذف أي سجل حيث Timestamp هو NULL.

تحديث (UPDATE)

  • يمكننا أيضًا الاستفادة من أمر UPDATE لتحديث بياناتك.
  • على سبيل المثال، يمكنك التنفيذ UPDATE favorites SET language = 'SQL', problem = 'Fiftyville';. سيؤدي هذا إلى تحديث كافة الصفوف.
  • لاحظ أن هذه الاستعلامات تتمتع بقوة هائلة. وفقًا لذلك، في بيئة العالم الحقيقي، يجب عليك التفكير في من لديه الأذونات لتنفيذ أوامر معينة وما إذا كان لديك نسخ احتياطية متاحة!

شجونه (IMDb)

  • يمكننا أن نتخيل قاعدة بيانات قد نرغب في إنشائها لفهرسة البرامج التلفزيونية المختلفة. يمكننا إنشاء جدول بيانات يحتوي على أعمدة مثل title, star, star, star, starوالمزيد من النجوم. مشكلة هذا الأسلوب هي أنه يحتوي على مساحة كبيرة مهدرة. قد تحتوي بعض العروض على نجمة واحدة. والبعض الآخر قد يكون لديه العشرات.
  • يمكننا تقسيم قاعدة البيانات الخاصة بنا إلى أوراق متعددة. يمكن أن يكون لدينا shows ورقة، أ stars ورقة، و people ورقة. على people ، يمكن أن يكون لكل شخص ميزة فريدة id. على shows ، يمكن أن يكون لكل عرض ميزة فريدة id أيضًا. على ورقة ثالثة تسمى stars يمكننا ربط الأشخاص بالعروض من خلال وجود show_id و person_id. على الرغم من أن هذا يعد تحسينًا، إلا أنه ليس قاعدة بيانات مثالية.
  • يقدم IMDb قاعدة بيانات للأشخاص والعروض والكتاب والنجوم والأنواع والتقييمات. ويرتبط كل من هذه الجداول ببعضها البعض على النحو التالي:

    six boxes that represent various sql tables arrows are drawn to each showing their many relationships with one another

  • بعد التنزيل shows.db، يمكنك التنفيذ sqlite3 shows.db في نافذتك الطرفية.
  • دعونا نركز على العلاقة بين جدولين داخل قاعدة البيانات المسماة shows و ratings. ويمكن توضيح العلاقة بين هذين الجدولين على النحو التالي:

    two boxes one called shows and the other called ratings

  • لتوضيح العلاقة بين هذه الجداول يمكننا تنفيذ الأمر التالي: SELECT * FROM ratings LIMIT 10;. فحص الإخراج، يمكننا التنفيذ SELECT * FROM shows LIMIT 10;.
  • الفحص shows و ratings، يمكننا أن نرى أن هناك علاقة فردية: عرض واحد له تقييم واحد.
  • لفهم قاعدة البيانات عند تنفيذها .schema لن تجد كل جدول من الجداول فحسب، بل ستجد الحقول الفردية داخل كل جدول من هذه الجداول.
  • وبشكل أكثر تحديدًا، يمكنك التنفيذ .schema shows لفهم الحقول الموجودة بداخله shows. يمكنك أيضًا التنفيذ .schema ratings لرؤية الحقول الموجودة بالداخل ratings.
  • يوجد مرجع لمعرف العرض في كافة الجداول. في جدول shows ، يُطلق عليه ببساطة id. يسمى هذا الحقل المشترك بين جميع الجداول أ . تُستخدم المفاتيح الأساسية لتحديد سجل فريد في الجدول. المفاتيح الخارجية يتم استخدام لبناء العلاقات بين الجداول من خلال الإشارة إلى المفتاح الأساسي في جدول آخر. يمكنك أن ترى في مخطط ratings ذلك show_id هو مفتاح خارجي يشير id في shows.
  • من خلال تخزين البيانات في قاعدة بيانات علائقية، كما هو مذكور أعلاه، يمكن تخزين البيانات بشكل أكثر كفاءة.
  • في سكليتي، لدينا خمسة أنواع من البيانات، بما في ذلك:

      BLOB       -- binary large objects that are groups of ones and zeros
      INTEGER    -- an integer
      NUMERIC    -- for numbers that are formatted specially like dates
      REAL       -- like a float
      TEXT       -- for strings and the like
    
  • بالإضافة إلى ذلك، يمكن تعيين الأعمدة لإضافة قيود خاصة:

      NOT NULL
      UNIQUE
    
  • يمكننا أيضًا اللعب بهذه البيانات لفهم هذه العلاقات. ينفذ SELECT * FROM ratings;. هناك الكثير من التقييمات!
  • يمكننا تقييد هذه البيانات بشكل أكبر من خلال التنفيذ SELECT show_id FROM ratings WHERE rating >= 6.0 LIMIT 10;. من هذا الاستعلام، يمكنك أن ترى أن هناك 10 عروض مقدمة. ومع ذلك، لا نعرف ما الذي يظهره كل منهما show_id يمثل.
  • يمكنك اكتشاف ما يظهر من خلال التنفيذ SELECT * FROM shows WHERE id = 626124;
  • يمكننا تحسين استعلامنا ليكون أكثر كفاءة من خلال تنفيذ:

    SELECT title
    FROM shows
    WHERE id IN (
        SELECT show_id
        FROM ratings
        WHERE rating >= 6.0
        LIMIT 10
    );
    

    لاحظ أن هذا الاستعلام يجمع استعلامين معًا. يتم استخدام الاستعلام الداخلي بواسطة استعلام خارجي.

JOINs

  • نحن نقوم بسحب البيانات من shows و ratings. لاحظ كيف على حد سواء shows و ratings لديك id مشتركة.
  • كيف يمكننا دمج الجداول مؤقتًا؟ يمكن ربط الجداول ببعضها باستخدام أمر JOIN .
  • قم بتنفيذ الأمر التالي:

    SELECT * FROM shows
      JOIN ratings ON shows.id = ratings.show_id
      WHERE rating >= 6.0
      LIMIT 10;
    

    لاحظ أن هذا يؤدي إلى جدول أوسع مما رأيناه سابقًا.

  • حيث أوضحت الاستعلامات السابقة واحد لواحد العلاقة بين هذه المفاتيح، دعونا نتفحص بعضها واحد لكثير العلاقات. التركيز على جدول genres ، قم بتنفيذ ما يلي:

    SELECT * FROM genres
    LIMIT 10;
    

    لاحظ كيف يوفر لنا هذا فكرة عن البيانات الأولية. قد تلاحظ أن العرض الواحد له ثلاث قيم. هذه علاقة رأس بأطراف.

  • يمكننا معرفة المزيد عن genres الجدول عن طريق الكتابة .schema genres.
  • قم بتنفيذ الأمر التالي لمعرفة المزيد حول الأفلام الكوميدية المتنوعة في قاعدة البيانات:

    SELECT title FROM shows
    WHERE id IN (
      SELECT show_id FROM genres
      WHERE genre = 'Comedy'
      LIMIT 10
    );
    

    لاحظ كيف ينتج عن ذلك قائمة من الأفلام الكوميدية، بما في ذلك كاتويزل.

  • يمكننا معرفة المزيد عن Catweazle من خلال الانضمام إلى الجداول المختلفة:

    SELECT * FROM shows
    JOIN genres
    ON shows.id = genres.show_id
    WHERE id = 63881;
    

    لاحظ أن هذا يؤدي إلى جدول مؤقت. من الجيد أن يكون لديك جدول مكرر. علاوة على ذلك، لاحظ أنه تم تعيين Catweazle (عنوان واحد). كثيرة الأنواع، بما في ذلك المغامرة والكوميديا والعائلة.

  • على النقيض من علاقات رأس برأس وعلاقة رأس بأطراف، هناك متعدد إلى متعدد العلاقات. على سبيل المثال، يمكن أن يظهر العديد من الأشخاص في العديد من العروض!
  • يمكننا معرفة المزيد عن العرض المكتب والممثلين في هذا العرض عن طريق تنفيذ الأمر التالي:

    SELECT name FROM people WHERE id IN 
        (SELECT person_id FROM stars WHERE show_id = 
            (SELECT id FROM shows WHERE title = 'The Office' AND year = 2005));
    

    لاحظ أن هذا يؤدي إلى جدول يتضمن أسماء النجوم المختلفة من خلال الاستعلامات المتداخلة.

  • يمكننا العثور على جميع العروض التي قام ببطولتها ستيف كاريل:

    SELECT title FROM shows WHERE id IN 
        (SELECT show_id FROM stars WHERE person_id = 
            (SELECT id FROM people WHERE name = 'Steve Carell'));
    

    ينتج عن هذا قائمة بعناوين العروض التي قام ستيف كاريل ببطولتها.

  • يمكن التعبير عن هذا كـ a JOIN كـ:

    SELECT title FROM shows
    JOIN stars ON shows.id = stars.show_id
    JOIN people ON stars.person_id = people.id
    WHERE name = 'Steve Carell';
    
  • يمكن أيضًا التعبير عن ذلك بهذه الطريقة:

    SELECT title FROM shows, stars, people 
    WHERE shows.id = stars.show_id
    AND people.id = stars.person_id
    AND name = 'Steve Carell';
    
  • حرف البدل يمكن استخدام عامل التشغيل % للعثور على جميع الأشخاص الذين تبدأ أسماؤهم بـ Steve C عن طريق استخدام الصيغة التالية: SELECT * FROM people WHERE name LIKE 'Steve C%';.

الفهارس (Indexes)

  • في حين أن قواعد البيانات العلائقية لديها القدرة على أن تكون أسرع وأكثر قوة من استخدام CSV ، يمكن تحسين البيانات داخل الجدول باستخدام الفهارس.
  • يمكن استخدام الفهارس لتسريع استعلاماتنا.
  • يمكننا تتبع سرعة استعلاماتنا من خلال التنفيذ .timer on في sqlite3.
  • لفهم كيف يمكن للفهارس تسريع استعلاماتنا، قم بتشغيل ما يلي: SELECT * FROM shows WHERE title = 'The Office'; لاحظ الوقت الذي يتم عرضه بعد تنفيذ الاستعلام.
  • بعد ذلك، يمكننا إنشاء فهرس بالصيغة CREATE INDEX title_index ON shows (title);. هذا يحكي sqlite3 لإنشاء فهرس وإجراء بعض التحسينات الخاصة المتعلقة بهذا العمود title.
  • سيؤدي هذا إلى إنشاء بنية بيانات تسمى أ شجرة ب، بنية بيانات تشبه الشجرة الثنائية. ومع ذلك، على عكس الشجرة الثنائية، يمكن أن يكون هناك أكثر من عقدتين تابعتين.

    one node at the top from which come four children and below that there are three children coming from one of the nodes and two from another two from another and three from another

  • علاوة على ذلك، يمكننا إنشاء فهارس على النحو التالي:

    CREATE INDEX name_index ON people (name);
    CREATE INDEX person_index ON stars (person_id);
    
  • قم بتشغيل الاستعلام وستلاحظ أن الاستعلام يعمل بسرعة أكبر!

    SELECT title FROM shows WHERE id IN 
        (SELECT show_id FROM stars WHERE person_id = 
            (SELECT id FROM people WHERE name = 'Steve Carell'));
    
  • لسوء الحظ، قد تؤدي فهرسة جميع الأعمدة إلى استخدام مساحة تخزين أكبر. لذلك، هناك مقايضة لتحسين السرعة.

استخدام SQL في بايثون (Using SQL in Python)

  • للمساعدة في العمل مع SQL في هذه الدورة، يمكن استخدام مكتبة CS50 على النحو التالي في الشيفرة الخاصة بك:

    from cs50 import SQL
    
  • على غرار الاستخدامات السابقة لمكتبة CS50، ستساعدك هذه المكتبة في الخطوات المعقدة لاستخدام SQL داخل كود Python الخاص بك.
  • يمكنك قراءة المزيد حول وظيفة SQL لمكتبة CS50 في الوثائق.
  • باستخدام معرفتنا الجديدة، يمكننا الآن الاستفادة من Python إلى جانب SQL.
  • قم بتعديل الشيفرة الخاص بك لـ favorites.py على النحو التالي:

    # Searches database for popularity of a problem
    
    from cs50 import SQL
    
    # Open database
    db = SQL("sqlite:///favorites.db")
    
    # Prompt user for favorite
    favorite = input("Favorite: ")
    
    # Search for title
    rows = db.execute("SELECT COUNT(*) AS n FROM favorites WHERE problem = ?", favorite)
    
    # Get first (and only) row
    row = rows[0]
    
    # Print popularity
    print(row["n"])
    

    لاحظ ذلك تم الآن إنشاء db = SQL("sqlite:///favorites.db") يوفر لبيثون موقع ملف قاعدة البيانات. ثم السطر الذي يبدأ بـ rows ينفذ أوامر SQL باستخدام db.execute. في الواقع، يقوم هذا الأمر بتمرير بناء الجملة ضمن علامات الاقتباس إلى وظيفة db.execute . يمكننا إصدار أي أمر SQL باستخدام بناء الجملة هذا. علاوة على ذلك، لاحظ ذلك يتم إرجاع rows كقائمة من القواميس. في هذه الحالة، هناك نتيجة واحدة فقط، صف واحد، يتم إرجاعها إلى قائمة الصفوف كقاموس. يمكنك تنزيل هذا الرمز هنا.

ظروف السباق (Race Conditions)

  • يمكن أن يؤدي استخدام SQL في بعض الأحيان إلى حدوث بعض المشكلات.
  • يمكنك تخيل حالة حيث يمكن لعدة مستخدمين الوصول إلى نفس قاعدة البيانات وتنفيذ الأوامر في نفس الوقت.
  • قد يؤدي هذا إلى حدوث خلل حيث تتم مقاطعة الشيفرة بسبب تصرفات الأشخاص الآخرين. قد يؤدي هذا إلى فقدان البيانات.
  • ميزات SQL المضمنة مثل BEGIN TRANSACTION, COMMITو ROLLBACK يساعد في تجنب بعض مشكلات حالة السباق هذه.

هجمات حقن SQL (SQL Injection Attacks)

  • الآن، ومازلت تفكر في الشيفرة أعلاه، ربما تتساءل ما هو ? علامات الاستفهام تفعل أعلاه. إحدى المشاكل التي يمكن أن تنشأ في تطبيقات SQL في العالم الحقيقي هي ما يسمى هجوم الحقن. هجوم الحقن هو المكان الذي يمكن فيه لممثل خبيث إدخال كود SQL ضار.
  • على سبيل المثال، خذ بعين الاعتبار شاشة تسجيل الدخول كما يلي:

    login screen with username and password fields

  • بدون الحماية المناسبة في الشيفرة الخاصة بنا، يمكن لممثل سيء تشغيل تعليمات برمجية ضارة. خذ بعين الاعتبار ما يلي:

    rows = db.execute("SELECT COUNT(*) FROM users WHERE username = ? AND password = ?", username, password)
    

    لاحظ ذلك لأن ? في مكانه، ويمكن تشغيل التحقق من الصحة username و password قبل أن يتم قبولها بشكل أعمى بواسطة الاستعلام.

  • لا تثق أبدًا بشكل أعمى في مدخلات المستخدم.
  • باستخدام مكتبة CS50، ستقوم المكتبة تعقيم وقم بإزالة أي أحرف قد تكون ضارة.

التلخيص (Summing Up)

في هذا الدرس، تعلمت المزيد من بناء الجملة المتعلق ببايثون. علاوة على ذلك، تعلمت كيفية دمج هذه المعرفة مع البيانات في شكل ملفات ثابتة وقواعد بيانات علائقية. وأخيرا، تعلمت عن SQL. على وجه التحديد، ناقشنا…

  • قواعد بيانات الملفات الثابتة
  • قواعد البيانات العلائقية
  • أوامر SQL مثل SELECT, CREATE, INSERT, DELETEو UPDATE.
  • المفاتيح الأساسية والأجنبية
  • JOINs
  • الفهارس
  • استخدام SQL في بايثون
  • ظروف السباق
  • هجمات حقن SQL

نراكم في المرة القادمة!

أنهيت قراءة الملاحظات؟

يمكنك قراءة الدورة كاملة دون حساب. يصبح حفظ التقدم متاحًا بعد تفعيل الحساب، ويبقى محفوظًا بعد انتهاء العضوية.