SEND EMAIL BASED ON CONDITIONS (SAS) - email

I found the below code (untouched) in this forum which is very close to what i was looking for however am having some issues when tweaking;
data Millenium_Falcon;
han='1';
luke='0';
darth='0';
run;
filename myemail EMAIL
to="me#lando.com"
cc="me#lando.com"
from="me#lando.com"
subject="Millenium Falcon"
importance="HIGH"
;
data _null_;
set Millenium_Falcon ;
file myemail;
IF (Luke = '1' and Darth = '0') then do;
put "Han,";
put " ";
put "Look out for the asteroids.";
put " ";
put "Thank you.";
put " ";
put "Obi";
end;
else do;
put '!EM_ABORT!';
end;
stop;
run;
Before tweaking, this code works fine however when i try to point to my data set (removing Millennium_Falcon step above) which just contains meta data from dictionary.tables (libname,memname,modate) and change the if statement to
IF (memname = 'TEST' and datepart(modate) = date()) then do;
the email does not send. It is almost like the data step (below) must be present (acting like datalines) for this to work.
data Millenium_Falcon;
han='1';
luke='0';
darth='0';
run;
Any help would be much appreciated.
Many thanks
Aaron

You probably want something more like this that will abort when no records meet the criteria and otherwise generate a list of the values that do.
data _null_;
file myemail;
if _n_=1 and eof then put '!EM_ABORT!';
set have end=eof ;
where (memname = 'TEST' and datepart(modate) = date()) ;
put memname= modate= ;
run;

Related

Email not being sent and there is no error [SAS]

%let emailUsername = %scan(&sysparm,1,+);
%let email = %unquote(%str(&emailUsername.#example.com));
%let sasProgram = %scan(&sysparm,2,+);
%let todayDate = %sysfunc(today(),MMDDYYS10.);
%let timeNow = %sysfunc(time(),TIMEAMPM.);
FILENAME mail
EMAIL TO=%unquote(%str(%'&email.%'))
SUBJECT='SAS Job Complete: &todayDate. on &timeNow.'
CONTENT_TYPE="text/html";
DATA _NULL_;
file mail;
PUT "<body>";
PUT "<p>Hello,</p>";
PUT "<p>This is an email confirming that your SAS program [&sasProgram..sas] has successfully ran and finished.</p>";
PUT "<p>- Creators of the SAS Program</p>";
PUT "</body>";
Run;
I am trying to understand why an email is not being sent. If I hard code the email address in, it works but when I have variables passed through it doesn't work. There is no error in the log file in regards to me trying to send an email so I am assuming it was successful.
Is there something else I need to do or look at?
Here is what I did, I changed your userEmail assignment and it's working:
%let emailUsername = psamson6;
%let email = %unquote(%str(&emailUsername.#gmail.com));
%let sasProgram = %scan(&sysparm,2,+);
%let todayDate = %sysfunc(today(),MMDDYYS10.);
%let timeNow = %sysfunc(time(),TIMEAMPM.);
FILENAME mail
EMAIL TO=%unquote(%str(%'&email.%'))
SUBJECT='SAS Job Complete: &todayDate. on &timeNow.'
CONTENT_TYPE="text/html";
DATA _NULL_;
file mail;
PUT "<body>";
PUT "<p>Hello,</p>";
PUT "<p>This is an email confirming that your SAS program [&sasProgram..sas] has successfully ran and finished.</p>";
PUT "<p>- Creators of the SAS Program</p>";
PUT "</body>";
Run;

Add the date of creation to a filename in SystemVerilog

I need to create a report(.txt) and I want to reference each sessions of tests, so I wanted that for each simulations, I add the date to name of my report.
Like Report_01-19-2017-12:53.txt
So far I have been able to create either a file with the date inside with :
$system("date > sDate");
or display it on my simulation software with :
$system("date");
So far,My code look like :
string filename;
reg [8*30:1] data; // the date is of 29 characters in size
string sDate;
integer scan_file,data_file ;
initial begin
$system("date > data");
data_file = $fopen("data", "r");
scan_file = $fscanf(sDate,"%s", data);
$fclose("data");
[...]
filename = {filename,sDate};
Report_Task = $fopen(filename,"a"); [...]
end
sDate contains nothing, date contains the date...
I tried string and reg for filename and sDate
Instead of going through files to get the date, you could use svlib. Chapter 9 of the documentation illustrates how to get information about the current time.
Don't you mean
scan_file = $fscanf(data_file, "%s", sDate);
where, if the read is successful, scan_file will be equal to 1 (the number of items read). (So, you probably didn't want to call it scan_file.)

Formatting output in powershell

I'm attempting to write a powershell script and running into a problem that google can't seem to tell me how to fix. Basically, i have 4 variables:
$myDuration = $myObj.Duration
$mySubject = $myObj.Subject
$myStart = $myObj.Start
$myLocation = $myObj.Location
I'm trying to send an email where the body is:
"Your meeting ({0}) will begin {1}. It will be held at {2} and last approximately {3}." -f $mySubject,$myStart,$myLocation,$myDuration
Now, if I ONLY include one variable, it works just fine. For example, "Your meeting {0}" -f $myLocation correctly outputs the value stored in $myLocation.
WHen I include more then one, my output for each variable is the exact string "System.Object[]". (IE "Your meeting (System.Object[]) will begin System.Object[]. It will be held at System.Object[] and last approximately System.Object[].") Any ideas why it bugs when I include more then one variable? From everything I've read about on Google there shouldn't be an issue.
Thank you for your time. Editing for hopefully better clarification of my issue.
I suspect that one or more of the fields in $myObj is something other than a string and can't be converted to a string easily, and that's throwing the formatter off. Have a look at this code:
$myDuration = "Duration";
$mySubject = "Subject";
$myStart = "Starttime";
$myLocation = "Location";
"Your meeting ({0}) will begin {1}. It will be held at {2} and last approximately {3}." -f $mySubject,$myStart,$myLocation,$myDuration
$myObj = #{"Duration"=[int32]123456;"Subject"="Subject2";"Starttime"=(get-date);"Location"="Location2"};
$myDuration = $myObj.Duration;
$mySubject = $myObj.Subject;
$myStart = $myObj.Starttime;
$myLocation = $myObj.Location;
"Your meeting ({0}) will begin {1}. It will be held at {2} and last approximately {3}." -f $mySubject,$myStart,$myLocation,$myDuration
And my output is:
Your meeting (Subject) will begin Starttime. It will be held at Location and last approximately Duration.
Your meeting (Subject2) will begin 2/13/2014 10:30:39 PM. It will be held at Location2 and last approximately 123456.
It all works as expected.

Rails raw query for csv format, to be returned via controller

I was using active record to get my stories and then generate a CSV, the standard way as done in the rails cast. But I have a lot of rows and it takes minutes. I think if I could get posgresql to do the csv rendering, then I could save some time.
Heres what I have right now:
query = "COPY stories TO STDOUT WITH CSV HEADER;"
results = ActiveRecord::Base.connection.execute(query);
But the results are empty for this query:
=> #<PG::Result:0x00000006ea0488 #connection=#<PG::Connection:0x00000006c62fb8 #socket_io=nil, #notice_receiver=nil, #notice_processor=nil>>
2.0.0-p247 :053 > result.count
=> 0
A better way of knowing:
2.0.0-p247 :059 > result.to_json
=> "[]"
I suspect my controller will look something like this:
format.csv { send_data raw_results }
This works for normal queries, I just can't figure out the SQL syntax to have the CSV results returned to rails.
UPDATE
Got the CSV export from 120000 msec down to 290 msec
My model:
def self.to_csv(story_ids)
csv = []
conn = ActiveRecord::Base.connection.raw_connection
conn.copy_data("COPY (SELECT * FROM stories WHERE stories.id IN (#{story_ids.join(',')})) TO STDOUT WITH (FORMAT CSV, HEADER TRUE, FORCE_QUOTE *, ESCAPE E'\\\\');") do
while row = conn.get_copy_data
csv.push(row)
end
end
csv.join("\r\n")
end
My controller:
send_data Story.to_csv(Story.order(:created_at).pluck(:id))
AFAIK you need to use the copy_data method on the underlying PostgreSQL database connection for this:
- (Object) copy_data(sql)
call-seq:
conn.copy_data( sql ) {|sql_result| ... } -> PG::Result
Execute a copy process for transferring [sic] data to or from the server.
This issues the SQL COPY command via #exec. The response to this (if there is no error in the command) is a PG::Result object that is passed to the block, bearing a status code of PGRES_COPY_OUT or PGRES_COPY_IN (depending on the specified copy direction). The application should then use #put_copy_data or #get_copy_data to receive or transmit data rows and should return from the block when finished.
And there's even an example:
conn.copy_data "COPY my_table TO STDOUT CSV" do
while row=conn.get_copy_data
p row
end
end
ActiveRecord's wrapper for the raw database connection doesn't know what copy_data is but you can use raw_connection to unwrap it:
conn = ActiveRecord::Base.connection.raw_connection
csv = [ ]
conn.copy_data('copy stories to stdout with csv header') do
while row = conn.get_copy_data
csv.push(row)
end
end
That would leave you with an array of CSV strings in csv (one CSV row per array entry) and you could csv.join("\r\n") to get the final CSV data.
This answer builds up on the answer provided by #mu-is-too-short, but without a temporary object using streaming instead.
headers['X-Accel-Buffering'] = 'no'
headers["Cache-Control"] = 'no-cache'
headers["Transfer-Encoding"] = 'chunked'
headers['Content-Type'] = 'text/csv; charset=utf-8'
headers['Content-Disposition'] = 'inline; filename="data.csv"'
headers.delete('Content-Length')
sql = "SELECT * FROM stories WHERE stories.id IN (#{story_ids.join(',')})"
self.response_body = Enumerator.new do |chunk|
conn = ActiveRecord::Base.connection.raw_connection
conn.copy_data("COPY (#{sql.chomp(';')}) TO STDOUT WITH (FORMAT CSV, HEADER TRUE, RCE_QUOTE *, ESCAPE E'\\\\');") do
while row = conn.get_copy_data
chunk << "#{row.length.to_s(16)}\r\n"
chunk << row
chunk << "\r\n"
end
chunk << "0\r\n\r\n"
end
end
You can also use gz = Zlib::GzipWriter.new(Stream.new(chunk)) and gz.write row with a class akin to
class Stream
def initialize(block)
#block = block
end
def write(row)
#block << "#{row.length.to_s(16)}\r\n"
#block << row
#block << "\r\n"
end
end
And remember headers['Content-Encoding'] = 'gzip'. See also this gist.

SAS Reading multiple records from one line without Line Feed CRLF

I have only 1 line without line feed (CRLF CRLF), the linefeed is a string of 4 characters, in this example is "#A$3" I don't need dlm for now, and I need to import it from a external file (/files/Example.txt)
JOSH 30JUL1984 1011 SPANISH#A$3RACHEL 29OCT1986 1013 MATH#A$3JOHNATHAN 05JAN1985 1015 chemistry
I need this line into 3 lines:
JOSH 30JUL1984 1011 SPANISH
RACHEL 29OCT1986 1013 MATH
JOHNATHAN 05JAN1985 1015 chemistry
How I can do that in SAS?
*Added: Your solutions are working with this example, but i have a issue, a line that contains more than the maximum length allowed for the line(32,767 bytes),
For example this line in the above exercise contains 5,000 records.
Is it possible?
Use the DLMSTR= option on the infile statement -- this will specify "#A$3" as the delimiter. Then use ## on the input statement to tell SAS to look for more records on the same line.
data test;
infile "/files/Example.txt" dsd dlmstr='#A$3';
informat var $255.;
input var $ ##;
run;
With your example, you will get a data set with 3 records with 1 variable containing the strings you are looking for.
Adjust the length of var as needed.
You could do something like this:
First import the file as a single row (be sure to adjust the length):
DATA WORK.IMPORTED_DATA;
INFILE "/files/Example.txt" TRUNCOVER;
LENGTH Column1 $ 255;
INPUT #1 Column1 $255.;
RUN;
Then parse imported data into variables using a data step:
data result (keep=var1-var4);
set WORK.IMPORTED_DATA;
delim = '#A$3';
end = 1;
begin = 1;
do while (end > 0);
end = find(Column1, delim, begin);
row = substr(Column1, begin, end - begin);
var1 = scan(row, 1);
var2 = scan(row, 2);
var3 = scan(row, 3);
var4 = scan(row, 4);
begin = end + length(delim);
output;
end;
run;
Try this in data step by viewing #A$3 as a multi-character delimiter:
data want (keep=subject);
infile 'C:\sasdata\test.txt';
input;
length line $4500 subject $80;
line=tranwrd(_infile_,"#A$3",'!');
do i=1 by 1 while (scan(line,i,'!') ^= ' ');
subject=scan(line,i,'!');
output;
end;
run;
_infile_ gives the current row that is being read in the data step. I converted the multi-character delimiter #A$2 into a single-character delimiter. tranwrd() can replace a sub-string inside a string. And then use the delimiter inside the scan() function.
Also, if you want to break the values up into separate variables, just scan some more. E.g. put something like B = scan(subject,2); into do loop and data want (keep= A B C D);. Cheers.