את כל העץ הזה, וענפים נוספים נרצה להכניס לתוך טבלה אחת שהקישוריים בין כל רמה לתת רמה שלה יהיו מצוינים בתוך כל רשומה בחלק ממנה
תחילה נקים טבלה חדשה tbllTree:
if exists (select * from dbo.sysobjects where id = object_id(N[dbo].[tblTree]) and
OBJECTPROPERTY(id, NIsUserTable) = 1)
drop table [dbo].[tblTree]
GO
CREATE TABLE [dbo].[tblTree] (
[Id] [int] IDENTITY (1, 1) NOT NULL ,
[Parent_Id] [int] NULL ,
[Name] [varchar] (150) NULL
)
ON [PRIMARY]
GO
בטבלה יהיו 3 שדות: ID שאינו מאפשר ערך NULL והוא IDENTITY PARENT_ID שהנו ערך מספרי Integer ושדה בערך של מחרוזת בגודל של 20 תווים
כל אלמנט בטבלה יקבל את ID אוטומטי כאשר ה PARENT_ID יהיה הערך ID של האבא של האלמנט. לאלמנטים הראשיים ניתן PARENT_ID = 0
אם נסתכל על העץ למעלה אז כאשר נכניס את הנתונים לטבלה, נכניס אותם בצורה הבאה: שרת/לקוח, אינטרנט, ומערכות הפעלה יקבלו כל אחד את ה PARENT_ID כ 0, ה ID שלהם יהיה 1 לשרת/לקוח 2 לאינטרנט ו 3 למערכות ההפעלה. כעט נכניס את הבנים הראשונים לכל אב עליון. שפות תיכנות, ומחוללי ישומיים יקבלו את ה ID של השרת/לקוח שכאמור הוא 1 כ PARENT_ID כאשר ה ID שלהם יתחולל אוטומטי ע"י בסיס הנתונים. במקרה שלנו זה יהיה 4 ו 5. שפות תיכנות, ושרתיים יקבלו את ה PARENT_ID של האינטרנט 2 וה ID שלהם יהיה 6 ו 7
עכשיו שנרצה להכניס בנים לשפות תיכנות תחת אינטרנט, ניתן להם את ה ID של השפות תיכנות שהוא כאמור 6 כ PARENT_ID, ואם נרצה להכניס סוגי שרתים תחת שרתים ניתן להם את ה ID של השרתים, כאמור 7. כ PARENT_ID.
וככה אנחנו יכולים להמשיך לבנות עץ הירארכי אין סופי שכל אלמנט מצביע עם הערך בשדה PARENT_ID על האבא שלו.
אבל כרגע אנחנו עוסקים ב 3 רמות בלבד.
כדי להוציא את הנתונים הללו בשיטות סטנדרטיות של פניה לבסיס נתונים קרוב לודאי שהיינו עובדים בשיטה הבאה:
Set oConn=server.createObject(“ADODB.Connection)
StrConnection = “My Server Connection String”
oConn.open strConnection
strSQL=”Select * from tblTree WHERE Parent_ID = 0”
set rs = oConn.execute(strSQL)
While not rs.eof
Response.write rs(“name”)
StrSQL1=”Select * from tblTree WHERE Parent_ID = “ & rs(“parent_id”)
set rs1 = oConn.execute(strSQL1)
While not rs1.eof
Response.write rs1(“name”)
StrSQL2=”Select * from tblTree WHERE Parent_ID = “ & rs1(“parent_id”)
set rs2 = oConn.execute(strSQL2)
While not rs2.eof
Response.write rs2(“name”)
Rs2.movenext
wend
rs1.movenext
wend
rs.movenext
wend
על הפנים, נכון? בשיטה הזאת אנחנו מפציצים את בסיס הנתונים בשאילתותת לא היה יותר טוב אם היינו יכולים לקבל את כל השדות בטבלה ברקורד סט אחד, כאשר המבנה ההירארכי כבר בתוכו, כפי שעשינו בקוד למעלה?
אפשר גם אפשר בעזרת ה DATASHAPE Provider
ה DATASHAPE Provider הוא חלק של ה ODBC בתוך הקומפוננט ADO, אני שלעצמי מעדיף להשתמש ב OLEDB כאשר אני פונה לבסיס נתונים, אבל במקרה הזה ב OLEDB הוא לא נמצא.
ה CONNECTION STRING:
strConnection= "Driver={SQL Server};Server=MyServer;
Provider=MSDataShape;Uid=MyUser;Pwd=MyPSW;Database=MyDatabase;AutoTranslate=No"
פתיחת הקונקשיין:
set cn = Server.Createobject("Adodb.connection")
set rsDS = Server.Createobject("adodb.recordset")
cn.Provider = "MSDataShape"
cn.Open strConnection
בניית משפט ה SQL:
strSQL = "SHAPE (SHAPE {SELECT * FROM tblTree where parent_id = 0} " & _
"APPEND((SHAPE{SELECT * FROM tblTree} " & _
"APPEND({SELECT * FROM tblTree} " & _
"RELATE ID to Parent_Id ) AS secLevel) " & _
"RELATE ID to Parent_Id) AS flevel) AS level"
שימו לב לאיך המשפט בנוי. בעצם יש לנו כאן שלושה משפטי SQL (משפט לכל רמה בעץ) המשפטים עצמם סגורים בתוך סוגריים מסולסלות ומילת המפתח לציון הרמות עצמן היא ה SHAPE כאשר ההפניה בין רמה לרמה מצויינת ע"י APPAND. הקשר אב בן בין רמה לרמה מצויין ע"י המילה RELATE שאם תשימו לב זה תמיד ID ל PARENT_ID.
כאשר נריץ את משפט ה SQL הזה מול בסיס הנתונים התוצאה תהיה רקורד סט הירארכי שמכיל את כל הנתונים בצורת עץ. set rsDS = cn.Execute(strSQL)
עכשיו ברצוננו להוציא את הנתונים מתוך הרקורד סט ולהציגם על המסך. אבל לפני זה מספר מילים על אייך בנוי הרקורד סט הזה. בעיקרון הוא בנוי כמו כל רקורד סט, אוסף של רשומות שאפשר לרוץ עליהם בלופ רגיל ולקבל את הערכים ממנו. אך נוסף לשדות הרגילים, נוסף לו בכל רשומה שדה נוסף שבעצם מכיל את הרקורד סט של הבן של אותו שדה. כלומר ברשומה הראשונה של הרקורד סט שמכיל את כל הרשומות אב (שה PARENT_ID שלהם שווה 0) יש את השדות ID, PARENT_ID ו NAME שמכילים את הערכים 1, 0 ו שרת/לקוח, הרשומה השניה תכיל את הערכים 2 , 0 , ואינטרנט וכן הלאה. אבל כל רשומה מכילה שדה נוסף שנקרא level או אם לא צויין שמו אז הוא השדה הרביעי ברשומה, במקרה שלנו. (אם הטבלה מכילה יותר שדות הוא בכל מקרה יהיה השדה האחרון) . השדה הזה מכיל עוד רקורדסט שבנוי בדיוק באותה צורה כמו הרקורד סט הראשון וכולל את כל הבנים של הרשומה מהרקורד סט הראשון, כלומר הרשומה הראשונה תכיל ID שהוא במקרה שלנו 4 ה PARENT_ID יהיה 1 והשדה NAME יכיל את הערך שפות תיכנות. הרשומה הבאה תכיל את הערכים 5, 1, ומחוללי ישומים. לכל אחת מהרשומות יהיה שדה נוסף (השדה האחרון) שיכיל את הבנים של אותה רשומה, אם יש בנים לאותה רשומה בטבלה.
כיצד נציג את הרקורד סט למשתמש שלנו while not rsDS.eof
נטייל על הרקורד סט כמו שאנחנו רגילים
Response.write rsDS(“name”) & “ ”
הצגנו את השדה שמכיל את הערך של האב העליון
עכשיו נוציא את הרקורד סט שנמצא בשדה האחרון
set lev2=rsDS.fields(“flevel”).value
ובעצם הפכנו את השדה האחרון לרקורד סט בפני עצמו, עכשיו אנחנו יכולים לטייל עליו
while not lev2.eof
Response.write “  ” & lev2 (“name”) & “ ”
ומהשדה האחרון נייצר רקורד סט נוסף
set lev3=lev2.fields(“secLevel”).Value
ושוב נטייל עליו
while not lev3.eof
Response.write “  “  ” & lev3 (“name”) & “ ”
וכמו בכל רקורדסט נעבור לרשומה הבאה ונמשיך
lev3.movenext
wend
כאשר נגמור את הסיבוב על הרמה השלישית, נמשיך לסובב את הרמה השניה
lev2.movenext
wend
וכמובן שאת הרמה הראשונה
rsDS.movenext
wend
ונסגור את הקונקשיין כפי שסוגרים קונקשניים
cn.Close
set cn = nothing
|