Alternativa metoder för sammanslagning av tabeller i SAS Fredrik Bernström och Johan Elfman Konsulter SAS Institute
Alternativa metoder för sammanslagning av tabeller i SAS Syfte med presentationen: Visa på alternativ till Merge och SQL Utöka verktygslådan Påvisa för- och nackdelar med de olika metoderna. 2
Alternativa metoder till Merge och SQL INTO & WHERE SET med KEY= option FORMAT HASH 3
Urval ur stor tabell sasforum.orders Order_ID... Customer_ID 1 9 2 2 3 6 4 2 5 7 6 9 7 5 8 6 9 8 10 1 11 8 12 8 13 11... sasforum.bad_customers Customer_ID 1 2 4 5 Indexerad på Customer_ID 4
Match-Merge data orders_subset; merge sasforum.bad_customers(in=a keep=customer_id) sasforum.orders(in=b); by customer_id; if a and b; run; 5
SQL Inner join proc sql; create table orders_subset as select a.* from sasforum.orders a, sasforum.bad_customers b where a.customer_id = b.customer_id ; quit; 6
SQL Select into Bygger på möjligheten att skapa makrovariabler med proc sql Kan användas för att göra enklare urval ur tabeller Har flera andra användningsområden, t.ex. att styra DO-loopar 7
SQL Select into proc sql noprint; select distinct customer_id into :subset separated by ', ' from sasforum.bad_customers; quit; data orders_subset; set sasforum.orders; where customer_id in (&subset); run; 8
SQL Select into proc sql noprint; select distinct customer_id into :subset separated by ', ' from sasforum.bad_customers; quit; data orders_subset; set sasforum.orders; where customer_id in (&subset); run; 9
SQL Select into proc sql noprint; select distinct customer_id into :subset separated by ', ' from sasforum.bad_customers; quit; data orders_subset; set sasforum.orders; where customer_id in (&subset); run; 10
SQL Select into proc sql noprint; select distinct customer_id into :subset separated by ', ' from sasforum.bad_customers; quit; data orders_subset; set sasforum.orders; where customer_id in (&subset); run; 11
SQL Select into proc sql noprint; select distinct customer_id into :subset separated by ', ' from sasforum.bad_customers; quit; data orders_subset; set sasforum.orders; where customer_id in (1, 2, 4, 5); run; 12
SQL Select into Fördelar: Data behöver ej vara sorterat eller indexerat Enkel programmering Har fler användningsområden än joins Nackdelar: Fungerar ej om urvalstabellen innehåller för många unika värden Nycklar endast på en variabel. 13
SET med KEY= option Datasteg med flera SET statements. Ger via index direktaccess till specifika rader i en tabell. Kan användas till såväl urval av rader i en stor tabell som slagning mot kodtabeller. 14
SET med KEY= option data orders_subset; set sasforum.bad_customers(keep=customer_id); set sasforum.orders key=customer_id; run; 15
SET med KEY= option data orders_subset; set sasforum.bad_customers(keep=customer_id); set sasforum.orders key=customer_id; if _iorc_ = %sysrc(_sok) then output; else if _iorc_ = %sysrc(_dsenom) then _error_=0; run; 16
SET med KEY= option data orders_subset; set sasforum.bad_customers(keep=customer_id); set sasforum.orders key=customer_id; if _iorc_ = %sysrc(_sok) then output; else if _iorc_ = %sysrc(_dsenom) then _error_=0; run; 17
SET med KEY= option data orders_subset; set sasforum.bad_customers(keep=customer_id); do until (_iorc_=%sysrc(_dsenom)); set sasforum.orders key=customer_id; if _iorc_ = %sysrc(_sok) then output; else if _iorc_ = %sysrc(_dsenom) then _error_=0; end; run; 18
SET med KEY= option Fördelar: Kan användas på osorterat data Kan hämta flera värden/kolumner i en slagning Kan nyckla på fler än en variabel (via komposit index) Nackdelar: Förhållandevis komplicerad kod Kräver index 19
Format Kan användas för att konvertera/översätta värden. Format kan skapas ifrån datakällor. Läses upp i minnet för snabb åtkomst. 20
Format Steg för steg - översikt 1. Utgå ifrån en tabell med ett nyckelvärde, och ett informationsvärde (t.ex. id resp. klartext). 2. Skapa en ny tabell med förutbestämda kolumnnamn 3. Skapa format genom att läsa in tabellen med proc format. 4. Använd formatet i ett datasteg. 21
Format - exempel Två tabeller: En tabell med orderinformation En tabell med produktkoder och produktnamn. 22
Format Två tabeller: En tabell med orderinformation En tabell med produktkoder och produktnamn. 23
Format Steg för steg 1. Utgå ifrån en tabell med ett nyckelvärde, och ett informationsvärde (t.ex. id resp. klartext). 2. Skapa en ny tabell med förutbestämda kolumnnamn 3. Skapa format genom att läsa in tabellen med proc format. 4. Använd formatet i ett datasteg. 24
Format En tabell med ett nyckelvärde en klartext 25
Format Steg för steg 1. Utgå ifrån en tabell med ett nyckelvärde, och ett informationsvärde (t.ex. id resp. klartext). 2. Skapa en ny tabell med förutbestämda kolumnnamn 3. Skapa format genom att läsa in tabellen med proc format. 4. Använd formatet i ett datasteg. 26
Format Kolumnnamn (måste): FMTNAME = Namn på formatet (utan $ och.) TYPE = N eller C START = Nyckelvärde LABEL = Etikett Kolumnnamn (ev): END = Vid numeriska intervallformat HLO = Typ av värde. T.ex. Other (O), High(H) 27
Format Skapa formattabell utifrån befintlig tabell data fmtin_data; length fmtname $32 type $1; retain fmtname 'prodfmt' type 'N'; set sasfdata.products(keep=product_id product_name); rename product_id = start product_name = label ; run; 28
Format En tabell med ett formatnamn ett formattypvärde ett startvärde / nyckelvärde en etikett / klartext 29
Format Steg för steg 1. Utgå ifrån en tabell med ett nyckelvärde, och ett informationsvärde (t.ex. id resp. klartext). 2. Skapa en ny tabell med förutbestämda kolumnnamn 3. Skapa format genom att läsa in tabellen med proc format. 4. Använd formatet i ett datasteg. 30
Format Skapa format utifrån formattabell proc format cntlin=fmtin_data; run; 31
Format Skapa format utifrån formattabell 25 proc format cntlin=fmtin_data; NOTE: Format PRODFMT has been output. 26 run; NOTE: PROCEDURE FORMAT used (Total process time): real time 0.15 seconds cpu time 0.04 seconds NOTE: There were 5579 observations read from the data set WORK.FMTIN_DATA. 32
Format Steg för steg 1. Utgå ifrån en tabell med ett nyckelvärde, och ett informationsvärde (t.ex. id resp. klartext). 2. Skapa en ny tabell med förutbestämda kolumnnamn 3. Skapa format genom att läsa in tabellen med proc format. 4. Använd formatet i ett datasteg. 33
Format Använd nyckelvärdet för att slå mot formatet och få tillbaka det formaterade värdet. data customer_orders; set custorders; length product_name $30; product_name = put(product_id, prodfmt.); run; 34
Format Komplett tabell: 35
Format data fmtin_data; length fmtname $32 type $1; retain fmtname 'prodfmt' type 'N'; set sasfdata.products(keep=product_id product_name); rename product_id = start product_name = label ; run; proc format cntlin=fmtin_data; run; data customer_orders; set custorders; length product_name $30; product_name = put(product_id, prodfmt.); run; 36
Format Fördelar: Ingen sortering av datakällor behövs Snabb exekvering Enkelt att använda. Nackdelar: Något komplicerat att skapa formatet Endast ett värde returneras per slagning. Endast ett nyckelvärde kan användas. Långsam vid stora datamängder. 37
Hash-objekt Nyhet i SAS9. Data Step Component Interface. Hash: Objekt i minnet som går mycket fort att söka i m.h.a. nyckelvärden (direct-addressing). Läs in en (eller flera) tabeller i minnet och använd dem för att hitta värden. 38
Hash-objekt 12 7 16 5 10 14 18 3 6 13 15 3 5 6 7 10 12 13 14 15 16 18 39
Hash, binärsökning Antal tester om man har 1.000 värden: Sekvensiellt medelvärde: 500 Binärsökning, (max): 10 Antal tester om man har 1.000.000 värden: Sekvensiellt medelvärde: 500.000 Binärsökning, (max): 20 40
Hash Steg för steg. Inne i data steget: 1. Deklarera variabler som ej finns i huvudtabell. 2. Initiera variabler som ej finns i huvudtabell. 3. Deklarera hash-objektet. 4. Läs in tabell i till hashobjektet 5. Starta läsning av grunddata, och slå mot hashobjektet. 41
Hash data outtable; set custorders; length product_name $45; if _n_ = 1 then do; call missing(product_name); declare hash prod(dataset: "sasfdata.products", hashexp: 8); prod.definekey('product_id'); prod.definedata('product_name'); prod.definedone(); end; rc = prod.find(); run; 42
Hash Steg för steg. Inne i data steget: 1. Deklarera variabler som ej finns i huvudtabell. 2. Initiera variabler som ej finns i huvudtabell. 3. Deklarera hash-objektet. 4. Läs in tabell i till hashobjektet 5. Starta läsning av grunddata, och slå mot hashobjektet. 43
Hash data outtable; set custorders; length product_name $45; if _n_ = 1 then do; call missing(product_name); 44
Hash Steg för steg. Inne i data steget: 1. Deklarera variabler som ej finns i huvudtabell. 2. Initiera variabler som ej finns i huvudtabell. 3. Deklarera hash-objektet. 4. Läs in tabell i till hashobjektet 5. Starta läsning av grunddata, och slå mot hashobjektet. 45
Hash declare hash prod(dataset: "sasfdata.products", hashexp: 8); 1. Deklarera objektet 2. Namn 3. Inkälla 4. Hash-exponent (storlek) 46
Hash declare hash prod(dataset: "sasfdata.products", hashexp: 8); 1. Deklarera objektet 2. Namn 3. Inkälla 4. Hash-exponent (storlek) 47
Hash declare hash prod(dataset: "sasfdata.products", hashexp: 8); 1. Deklarera objektet 2. Namn 3. Inkälla 4. Hash-exponent (storlek) 48
Hash declare hash prod(dataset: "sasfdata.products", hashexp: 8); 1. Deklarera objektet 2. Namn 3. Inkälla 4. Hash-exponent (storlek) 49
Hashexponent Hashexp anger hur många Hash-buckets man skall ha. En Bucket är ett binär-träd. Värdet är en exponent ( Antal = 2 ** Hashexp) Alltså ger hashexp=2 nedan. 4 st buckets, enligt bild 50
Hash Steg för steg. Inne i data steget: 1. Deklarera variabler som ej finns i huvudtabell. 2. Initiera variabler som ej finns i huvudtabell. 3. Deklarera hash-objektet. 4. Läs in tabell i till hash-objektet 5. Starta läsning av grunddata, och slå mot hashobjektet. 51
Hash objekt: Metoder definekey() Vilket värde är nyckel? definedata() Vilket värde skall lagras? definedone() Slut på deklarationen av objektet. declare hash prod(dataset: "sasfdata.products", hashexp: 8); prod.definekey('product_id'); prod.definedata('product_name'); prod.definedone(); 52
Hash Steg för steg. Inne i data steget: 1. Deklarera variabler som ej finns i huvudtabell. 2. Initiera variabler som ej finns i huvudtabell. 3. Deklarera hash-objektet. 4. Läs in tabell i till hashobjektet 5. Starta läsning av grunddata, och slå mot hash-objektet. 53
Hash objekt: Metoder find() Hitta värde? add, remove, replace, check, num_items, delete, output... /* Nyckelvärdesvariabel skapad innan med rätt namn och med värde */ rc = prod.find(); Om rc = 0 så finns nyckelvärdet i hash-objektet. 54
Hash data outtable; set custorders; length product_name $45; if _n_ = 1 then do; call missing(product_name); declare hash prod(dataset: "sasfdata.products", hashexp: 8); prod.definekey('product_id'); prod.definedata('product_name'); prod.definedone(); end; rc = prod.find(); run; 55
122 data Hash outtable; 123 set custorders; 124 length product_name $45; 125 if _n_ = 1 then do; 126 call missing(product_name); 127 128 declare hash prod(dataset: "sasfdata.products", hashexp: 8); 129 prod.definekey('product_id'); 130 prod.definedata('product_name'); 131 prod.definedone(); 132 end; 133 rc = prod.find(); 134 run; Hash - Log NOTE: There were 5579 observations read from the data set SASFDATA.PRODUCTS. NOTE: There were 15 observations read from the data set WORK.CUSTORDERS. NOTE: The data set WORK.OUTTABLE has 15 observations and 8 variables. NOTE: DATA statement used (Total process time): real time 0.01 seconds Fredrik Bernström cpu time & Johan Elfman, SAS Institute 0.02 AB seconds 56
Hash tre tabeller 57
data orderswithprodsup; set custorders; length product_name $45 supplier_id 8 supplier_name country $40; if _n_ = 1 then do; declare hash prod(dataset: "sasfdata.products", hashexp: 8); prod.definekey('product_id'); prod.definedata('product_name'); prod.definedata('supplier_id'); prod.definedone(); declare hash sup(dataset: "sasfdata.supplier", hashexp: 8); sup.definekey('supplier_id'); sup.definedata('supplier_name'); sup.definedata('country'); sup.definedone(); call missing(product_id, product_name, supplier_id, supplier_name, country); end; rc = prod.find(); rc2 = sup.find(); format country $COUNTRY.; run; 58
Hash tre tabeller NOTE: There were 5579 observations read from the data set SASFDATA.PRODUCTS. NOTE: There were 64 observations read from the data set SASFDATA.SUPPLIER. NOTE: There were 15 observations read from the data set WORK.CUSTORDERS. NOTE: The data set WORK.ORDERSWITHPRODSUP has 15 observations and 12 variables. NOTE: DATA statement used (Total process time): real time 0.03 seconds cpu time 0.04 seconds 59
Hash tre tabeller 60
Hash Fördelar: Snabbt (in memory) Flexibelt (En eller flera tabeller, sortering, många till många) Nackdelar: Man får ej med kolumnattribut från inlästa tabeller Annorlunda programmering än vad vi är vana vid. 61
Vad avgör val av teknik? Programmerarens kunskaper Förvaltning Prestanda Viljan att prova på nya saker och utvecklas! 62
63