BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Yul
Obsidian | Level 7 Yul
Obsidian | Level 7

שלום, 

איך ניתן לסנן לפני המיזוג רק קבצים שיש בהם מידע - רשומות?

אני רוצה למזג עשרות של קבצים כאשר לעתים יש בהם מידע ולעתים לא.

בדקתי את האופציות שרשומות בפורום באנגלית והם לא נותנות לי מענה שאני מצליחה ליישם. 

 

1 ACCEPTED SOLUTION

Accepted Solutions
EyalGonen
Lapis Lazuli | Level 10

שלום @Yul 

 

השליפה ב SQL מייצרת משתנה מאקרו של SAS שמכיל את התוצאה של ה SELECT. במקרה שלך משתנה המאקרו שנקרא NAMES מכיל את שמות כל הטבלאות שנמצאות ב Library שמופיע בפקודת ה WHERE.

אנסה להסביר: יש ב SAS טבלאות שנקראות טבלאות dictionary שהן מובנות ב SAS. טבלאות אלה מתעדכנות אוטומטית בכל פעם שעושים Libname או מייצרים קובץ SAS חדש או מוחקים קובץ SAS וכד'.

ה SQL בעצם שולף מאותו dictionary (במקרה זה) את רשימת קבצי ה SAS שנמצאים *כרגע* בספריה שמופיעה בפקודת ה WHERE (ללא פקודת ה WHERE נקבל את רשימת כל קבצי ה SAS בכל ה Libnames) ושומר את התוצאה = רשימת קבצי ה SAS במשתנה מאקרו. אח"כ אפשר להשתמש במשתנה המאקרו הזה בכל מקום שרוצים לדוגמה בפקודת merge ב data step שמופיע מיד לאחר ה SQL.

 

האם עניתי לשאלה?

View solution in original post

11 REPLIES 11
arielbud
SAS Employee

היי יוליה,
עשיתי שילוב בין
https://communities.sas.com/t5/SAS-Programming/Delete-empty-datasets-from-work-lib/td-p/103874

וגם
https://communities.sas.com/t5/SAS-Programming/Merge-all-datasets-in-library/td-p/97413


ויצרתי את הדוגמית מטה (אנא תבדקי האם זה עוזר)

 

בברכה

אריאל

/* creating library and 3 datasets as example*/

libname YUL "C:\temp";

data yul.class1 ;

set sashelp.class;

run;

data yul.a;

set sashelp.class;

name1="אריאל";

run;

data yul.class2;

num=.;

Name='';

run;

/* if your datasets begin with same letters */

/* data want;*/

/* merge c:;*/

/* by name;*/

/* run;*/

/* begin with different letters */

proc sql noprint;

select memname into : names

from dictionary.tables

where libname='YUL' and nobs ne 0; /* note: libname must be in upcase */

data yul.final;

merge &names ;

by name;

run;

Yul
Obsidian | Level 7 Yul
Obsidian | Level 7

היי אריאל,

את החלק הראשון אני כבר מיישמת. את החלק השני של הSQL לא לגמרי מבינה. תוכל לרשום בבקשה ליד כל שורה בפקודת הSQL מה היא אמורה לעשות ומה צריך לשנות שם.

יצרתי מספר מיזוגים של קבצים שמתחילים באותן תחיליות ושמרתי אותם עם תחילית all_name  - הNAME משתנה ושמרתי אותם בספריה lib.

 

proc sql noprint;

select memname into : names

from dictionary.tables

where libname='YUL' and nobs ne 0;  -  אני מניחה שהYUL זה הLIB

אבל מה אמורים להיות הפרמטרים שאני מכניסה לפקודה המודגשת בקו תחתון?

data yul.final;

merge &names ;

by name;

run;

 

EyalGonen
Lapis Lazuli | Level 10

שלום @Yul 

 

השליפה ב SQL מייצרת משתנה מאקרו של SAS שמכיל את התוצאה של ה SELECT. במקרה שלך משתנה המאקרו שנקרא NAMES מכיל את שמות כל הטבלאות שנמצאות ב Library שמופיע בפקודת ה WHERE.

אנסה להסביר: יש ב SAS טבלאות שנקראות טבלאות dictionary שהן מובנות ב SAS. טבלאות אלה מתעדכנות אוטומטית בכל פעם שעושים Libname או מייצרים קובץ SAS חדש או מוחקים קובץ SAS וכד'.

ה SQL בעצם שולף מאותו dictionary (במקרה זה) את רשימת קבצי ה SAS שנמצאים *כרגע* בספריה שמופיעה בפקודת ה WHERE (ללא פקודת ה WHERE נקבל את רשימת כל קבצי ה SAS בכל ה Libnames) ושומר את התוצאה = רשימת קבצי ה SAS במשתנה מאקרו. אח"כ אפשר להשתמש במשתנה המאקרו הזה בכל מקום שרוצים לדוגמה בפקודת merge ב data step שמופיע מיד לאחר ה SQL.

 

האם עניתי לשאלה?

Assaf_Attas
Obsidian | Level 7

הי אריאל / מרים

לקטע ה- SQL יש לצרף גם פקודת separated by על מנת שזה יעבוד.

לא ברור מה הצורך האמיתי בבדיקת קובץ ריק כן / לא

פקודת SET של סאס יודעת להתמודד גם עם קבצים ריקים.

למעשה - אין הבדל האם קבצים ריקים נכללים בפקודת ה- SET או לא

proc sql noprint;
	select memname into : names separated by ' '
	from dictionary.tables
	where libname='WORK'
;
quit;
Assaf_Attas
Obsidian | Level 7

קצת הסתבכתי עם העברית / אנגלית

מנסה שוב

 

proc sql noprint;
select memname into : names separated by ' '
from dictionary.tables
where libname='WORK'
;
quit;
Yul
Obsidian | Level 7 Yul
Obsidian | Level 7

תודה רבה אסף על התשובה.

אני אסביר למה מיזוג בSET לא נותן לי את המענה הרצוי אליו אני מכוונת.

כאשר אני ממזגת הרבה קבצים קטנים שכל אחד מהם כולל משתנים רבים ושונים מקובץ לקובץ נוצר לי באמצעות הSET קובץ גדול שמכיל הרבה מאוד משתנים.

הייתי רוצה להגיע למצב שבו הקובץ הסופי יכיל את הקבצים שיש בהם תצפיות ורק את המשתנים שיש בהם מידע. לא בטוחה אם יש דרך לעשות זאת בכלל בסאס, האם יש לך פתרון יצירתי בשביל הבעיה הזו?  

EyalGonen
Lapis Lazuli | Level 10

שלום @Yul 

 

בפקודת set הוא לוקח אוטומטית את כל השדות בטבלה (למעט אלה שעושים להם drop או לחילופין רק את אלה שעושים להם keep). הוא לא בודק האם יש ערכים או לא.

דרך אגב, פקודת set לא ממזגת בכלל קבצים אלא במקרה הטוב עושה interleaving (שזירה) של קבצים או append לקבצים.

מי שממזג קבצים זו פקודת merge או על ידי שימוש ב PROC SQL.

ההתנהגות של פקודת merge בהקשר של שדות בדיוק כמו שתיארתי למעלה בהקשר של פקודת set.

שימי לב שגם בדוגמה ש @arielbud  שלח בהתחלה יש שימוש בפקודת merge לצורך המיזוג.

 

אם את יודעת מראש שיש שדות בעלי ערכים דומים (נניח מספר טלפון) בכל הטבלאות שאת ממזגת ואת רוצה את הערך הראשון הלא ריק בתור השדה בקובץ הפלט אזי אפשר להשתמש בפונקציה coalesce ב PROC SQL כלומר לעשות את המיזוג עם SQL ולא עם merge משהו כזה:

 

proc sql;

select coalesce(a.phone, b.phone, c.phone) as phone

from table1 as a, table2 as b, table3 as c

where <join condition>

 

מקווה שזה עוזר.

 

אייל

Yul
Obsidian | Level 7 Yul
Obsidian | Level 7

התכוונתי לאיחוד של קבצים ולכן הSET. מכירה את ההבדלים בין MERGE לSET. המינוח שלי בעברית לא היה מדויק. 

כאמור אני צריכה לעשות פעולת SET  או משהו דומה 

EyalGonen
Lapis Lazuli | Level 10

שלום @Yul 

 

לידיעה בלבד: אפשר לבצע איחוד קבצים גם עם PROC SQL על ידי האופרטור UNION

דוגמאות לשימוש ב UNION ואופרטורים נוספים אפשר למצוא כאן: https://documentation.sas.com/?docsetId=sqlproc&docsetTarget=n0vo2lglyrnexwn14emi8m0jqvrj.htm&docset...

 

אייל

Hagay
SAS Employee

שלום @Yul 

 

בנוסף להצעה של אייל נראה לי שהקוד הבא גם יכול לעזור לך.

הוא נראה קצת ארוך אבל הוא רק מורכב מכמה שלבים שכל אחד מהם די פשוט.

 

חגי

 

* Generating some sample tables;
data CLASS;
	set SASHELP.CLASS;
run;
data CLASS_EMPTY;
	set SASHELP.CLASS;
	length 
		Size	8
		Teacher	$30;
	call missing(of _all_);
	stop;
run;
data CLASS_HEB(rename=(weight=Miskal height=Gova Name=Shem age=Gil sex=Migdar));
	set SASHELP.CLASS;
	length 
		Teacher	$30;
	call missing(teacher);
run;

*** STEP 1: Appending all tables that are not empty ***;
* Getting all the names of the non empty tables into a macro variable;
* Note - this method will work only if all the tables are SAS tables (datasets);
* The LIBNAME and MEMNAME filters in the WHERE statement need to be 
*	updated to properly identify all the relevant tables;
proc sql noprint; 	
	select memname into :tables_list separated by " "
	from dictionary.tables 
	where libname="WORK" and memname like 'CLASS%' 
		and nobs>0;
quit;
%put &tables_list;

* Appending all the non empty tables into one large table;
data ALL_TABLES;
	set &tables_list;
run;

*** STEP 2: Finding columns that are all empty ***;
* This method is just one of the possible methods to accomplish this task. Google will offer several more; * Getting all the columns in the big table we have just created; proc sql noprint; create table ALL_TABLES_COLS as select name from dictionary.columns where libname="WORK" and memname = 'ALL_TABLES' ; quit; * Creating a SAS program to count the non missing number of values in each column; * Note - The COUNT function counts only non missing values; filename sascode temp; data _null_; set ALL_TABLES_COLS end=last; file sascode; if _n_=1 then do; put "proc sql noprint;"; put "create table ALL_TABLES_COLS_NMISS as select"; end; put "count(" name ") as " name @; if ^last then put ","; else do; put /"from ALL_TABLES;"; put "quit;"; end; run; * Running the SAS program our SAS program have just created!; %include sascode; * Transposing the tables with the number of distinct values in each column to rows; proc transpose data=ALL_TABLES_COLS_NMISS out=ALL_TABLES_COLS_NMISS_T(rename=(_name_=Variable_Name col1=Non_Missing_Values)); run; * Collecting the name of the columns that have at least one non missing value into a macro variable; proc sql noprint; select Variable_Name into :columns_list separated by " " from ALL_TABLES_COLS_NMISS_T where Non_Missing_Values>0; quit; %put &=columns_list; * Keeping only these columns - dropping the columns that contains all missing values; data ALL_TABLES; set ALL_TABLES(keep=&columns_list); run;
Yul
Obsidian | Level 7 Yul
Obsidian | Level 7

היי, זה לא פותר לי את הבעיה אבל התשובה שלך משלימה לי חלק מהמידע שהיה חסר לי, תודה רבה

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

Discussion stats
  • 11 replies
  • 1711 views
  • 5 likes
  • 5 in conversation