SAS: Read File scattered across lines - file-io

I have data in the .txt file as:
VALUE ADM_LN2G
1 = 'ENGLISH'
2 = 'FRENCH'
3 = 'ARABIC'
4 = 'CHINESE'
5 = 'CREE'
6 = 'GERMAN'
7 = 'GREEK'
;
VALUE ADM_LNG
24 = 'INUKTITUT'
90 = 'OTHER'
96 = 'NOT APPLICABLE'
97 = 'DON''T KNOW'
98 = 'REFUSAL'
99 = 'NOT STATED'
;
.
.
.
.
I want to separate out each value in different dataset.
Output expected:
Dataset 1 : ADM_LN2G
VALUE ADM_LN2G
1 = 'ENGLISH'
2 = 'FRENCH'
3 = 'ARABIC'
4 = 'CHINESE'
5 = 'CREE'
6 = 'GERMAN'
7 = 'GREEK'
;
Dataset 2: ADM_LNG
VALUE ADM_LNG
24 = 'INUKTITUT'
90 = 'OTHER'
96 = 'NOT APPLICABLE'
97 = 'DON''T KNOW'
98 = 'REFUSAL'
99 = 'NOT STATED'
;
etc.
For every VALUE there is ";" at the end.
Please help!
Thanks in advance!!

If the file is valid code for creating SAS formats then you can get at the data by letting SAS create the formats.
proc format lib=work.newformats;
%include "source file";
run;
Then use PROC FORMAT to export the formats to a data set.
proc format lib=work.newformats cntlout=WANT(keep=fmtname start label);
run;

Related

Select rows from related table which matches different conditions

I have a table called places which looks like this:
and another table called place_addons_saved which looks like this:
How can I write a query that relates place_addons_saved.place and places.id and searches rows that matches ONLY places which have all the conditions?
For example when I'll search for rows that have place_addon = 163, place_option = 329 and place_addon = 162, place_option = 324 will return place with id of a 80, but when I'll search for rows that have place_addon = 162, place_option = 326 and place_addon = 163, place_option = 330 the query must return nothing, because place 80 doesn't fit the 2nd condition
If I understand correctly, you can use group by and having:
select place
from place_addons_saved
where (place_addon = 163 and place_option = 329) or
(place_addon = 162 and place_option = 324)
group by place
having count(*) = 2; -- "2" is the number of comparisons
To get all the information about the places:
select p.*
from places p
where p.id in (select place
from place_addons_saved
where (place_addon = 163 and place_option = 329) or
(place_addon = 162 and place_option = 324)
group by place
having count(*) = 2; -- "2" is the number of comparisons
);
This could work:
With GetResult (place,chk1,chk2) As
(
SELECT
pas.place,
sum(Case When (pas.place_addon = 163) AND (pas.place_option = 329) then 1 Else 0 End) As chk1,
sum(Case When (pas.place_addon = 162) AND (pas.place_option = 324) then 1 Else 0 End) As chk2
FROM
places AS p RIGHT OUTER JOIN
place_addons_saved AS pas ON p.id = pas.place
group by pas.place
)
Select * From GetResult Where chk1 > 0 and chk2 > 0

Case statement and OR in SQL

Can someone please advise on the below? I have a number of fields which I would like to use and combine these to get the data in one column. I am using the following case statement but am not getting the results I expect.
CASE
WHEN m.u_hearing = 1 THEN 'Hearing'
WHEN m.u_learning_reading_diff = 1 THEN 'Learning or reading Difficulty'
WHEN m.u_long_term_ill = 1 THEN 'Long Term Illness'
WHEN m.u_mental_illness = 1 THEN 'Mental Illness'
WHEN m.u_mobility = 1 THEN 'Mobility'
WHEN m.u_physical_coordination = 1 THEN 'Physical Co-ordination'
WHEN m.u_physical_dis = 1 THEN 'Physical Disability'
WHEN m.u_red_physical_cap = 1 THEN 'Reduced_physical_capacity'
WHEN m.u_speech = 1 THEN 'Speech'
WHEN m.u_vision = 1 THEN 'Vision'
WHEN m.u_other_dis = 1 THEN 'Other_Disability'
WHEN (m.u_hearing = 1 AND (m.u_learning_reading_diff = 1 OR (m.u_speech = 1))) THEN 'Multiple'
It is the last statement that is not giving the result I would like as if there are multiple fields with Yes then I would like multiple returned but it seems it is picking the first case.
Put the "hardest" condition first
case WHEN m.u_hearing = 1 AND (m.u_learning_reading_diff = 1 OR m.u_speech = 1) THEN 'Multiple'
WHEN m.u_hearing = 1 THEN 'Hearing' ...
Because a case stops at the first condition that is true
When using CASE statements, they will function in the order you have specified.
So if m.u_Hearing = 1 then it will stop at the first line and not reach the bottom one.
This will work for what you require, however list it in the order you prefer.
CASE
WHEN (m.u_hearing = 1 AND (m.u_learning_reading_diff = 1 OR (m.u_speech = 1))) THEN 'Multiple'
WHEN m.u_hearing = 1 THEN 'Hearing'
WHEN m.u_learning_reading_diff = 1 THEN 'Learning or reading Difficulty'
WHEN m.u_long_term_ill = 1 THEN 'Long Term Illness'
WHEN m.u_mental_illness = 1 THEN 'Mental Illness'
WHEN m.u_mobility = 1 THEN 'Mobility'
WHEN m.u_physical_coordination = 1 THEN 'Physical Co-ordination'
WHEN m.u_physical_dis = 1 THEN 'Physical Disability'
WHEN m.u_red_physical_cap = 1 THEN 'Reduced_physical_capacity'
WHEN m.u_speech = 1 THEN 'Speech'
WHEN m.u_vision = 1 THEN 'Vision'
WHEN m.u_other_dis = 1 THEN 'Other_Disability'
From what I know you cannot use your first statement again in another "when" like your
WHEN m.u_hearing = 1 THEN 'Hearing'
Above condition try to use else if it is working and feasible for you in end.
Else 'Multiple'

How to read the position value given the cost center

I want to read the position using this FM HRWPC_RPT_COSTCENTER_EVALPATH where the cost center is given.
There are 3 result tables. from which table I can read the position value ?
here how I call the FM:
DATA i_hrrootob TYPE TABLE OF hrrootob.
DATA w_hrrootob LIKE LINE OF i_hrrootob.
DATA i_object_tab TYPE TABLE OF objec.
DATA w_object_tab LIKE LINE OF i_object_tab.
data i_STRUC TYPE TABLE OF STRUC.
w_hrrootob-otype = 'K'.
w_hrrootob-objid = w_orgdata-costcenter_key-costcenter.
APPEND w_hrrootob TO i_hrrootob.
CALL FUNCTION 'HRWPC_RPT_COSTCENTER_EVALPATH'
EXPORTING
depth = 0
evpath = 'KOSTDIUP'
* PLVAR = 01
* BEGDA = SY-DATUM
* ENDDA = SY-DATUM
* LEVEL = 1
TABLES
root_objects = i_hrrootob
result_objec = i_object_tab
result_struc = i_STRUC
EXCEPTIONS
NO_OBJECTS_FOUND = 1
OTHERS = 2
.
I got it by myself.
The result table result_objec has the value in the field stext, where the obtype ='S'

sql routine to export separate txt files

I have an sql query which is a pricelist that I normally run 18 different times for 18 different clients.
I have a #varchar as as declaration and I change the customerID. This then exports a txt flat-file file so then I can convert to Excel and send via feebootimail.
Is there a routine that I can run in sql 2005 so I can feed a list of customers into and get 18 different txt files? example Pricelist_8343.txt, Pricelist_8363.txt ect
DECLARE #CustNum varchar(20)
SELECT #CustNum = '7509'
SELECT
it.ITEMID 'item id'
,it.ItemGroupID
,it.ITEMNAME
,Convert(Decimal(9,0),itm.QUANTITY) 'Sales Multiple'
,Convert(Decimal(9,0),it.TAXPACKAGINGQTY) 'Price Break Qty'
,Convert(Decimal(9,0),it.OUTERQUANTITY) 'Carton Qty'
,Convert(Decimal(9,2),itm.PRICE) 'Part Pack'
,Convert(Decimal(9,2),itm.PRICE2) 'Full Pack'
,Convert(Decimal(9,2),round( CASE
WHEN pdt.AMOUNT >0 then pdt.amount
else CASE
when pdt.discpct is null then CASE
WHEN pdt.PRICELEVELTOUSE = 0 then Price
WHEN pdt.PRICELEVELTOUSE = 1 then Price2
WHEN pdt.PRICELEVELTOUSE = 2 then Price3
WHEN pdt.PRICELEVELTOUSE = 3 then Price4
WHEN pdt.PRICELEVELTOUSE = 4 then Price5
WHEN pdt.PRICELEVELTOUSE = 5 then Price6 END
when pdt.discpct = 0 then CASE
WHEN pdt.PRICELEVELTOUSE = 0 then Price
WHEN pdt.PRICELEVELTOUSE = 1 then Price2
WHEN pdt.PRICELEVELTOUSE = 2 then Price3
WHEN pdt.PRICELEVELTOUSE = 3 then Price4
WHEN pdt.PRICELEVELTOUSE = 4 then Price5
WHEN pdt.PRICELEVELTOUSE = 5 then Price6 END
when pdt.discpct > 0 then CASE
WHEN pdt.PRICELEVELTOUSE = 0 then round(itm.price - (itm.price*pdt.discpct/100),2)
WHEN pdt.PRICELEVELTOUSE = 1 then round(itm.price2 - (itm.price2*pdt.discpct/100),2)
WHEN pdt.PRICELEVELTOUSE = 2 then round(itm.price3 - (itm.price3*pdt.discpct/100),2)
WHEN pdt.PRICELEVELTOUSE = 3 then round(itm.price4 - (itm.price4*pdt.discpct/100),2)
WHEN pdt.PRICELEVELTOUSE = 4 then round(itm.price5 - (itm.price5*pdt.discpct/100),2)
WHEN pdt.PRICELEVELTOUSE = 5 then round(itm.price6 - (itm.price6*pdt.discpct/100),2) END END END ,2)) as 'TAPrice'
,upper(itm.unitid) 'UOM'
, Case
When itm.PRICECHANGESTATUS=3 then 'Increase'
When itm.PRICECHANGESTATUS=2 then 'Decrease'
When itm.PRICECHANGESTATUS=1 then 'New Item'
When itm.PRICECHANGESTATUS=0 then '-'
END 'Price Indicator'
from INVENTTABLE it
join INVENTTABLEMODULE itm on it.ItemId = itm.ItemID and itm.ModuleType = 2
join CUSTTABLE cust on LTRIM(cust.AccountNum) = #CustNum
left outer join PRICEDISCTABLE pdt on (ltrim(pdt.accountrelation) =
case
when pdt.accountcode = 0 then ltrim(cust.accountnum)
when pdt.accountcode = 1 then ltrim(cust.pricegroup) end)and
(ltrim(pdt.ItemRelation)+ltrim(pdt.UnitID) = case
when pdt.itemrelation = it.itemid then ltrim(it.ItemID)+ltrim(itm.Unitid)
when pdt.itemrelation = it.itempricegroup then ltrim(it.ItemPriceGroup)+ltrim(itm.Unitid)end
) and pdt.fromdate <= getdate() and (getdate()<= pdt.todate or pdt.todate = ' ')
join PriceLevelListReportLine sorter on it.ItemGroupID = sorter.ItemGroupID
and (it.ItemType = (case when sorter.linetype = 0 then '0'
when sorter.linetype = 1 then '0'
when sorter.linetype = 2 then '1'end)
or it.ItemType = (case when sorter.linetype = 1 then '1' end))
WHERE it.PRICELISTFlag=1
ORDER BY sorter.SortOrder, it.ItemID
You could do this with SQLCMD and a batch file.
Make a script.sql file with contents like:
declare #CustNum varchar(20) = '$(custnum)'
select
-- your giant query here
Then make a batch file that looks like this:
#echo off
set custnum=1234
call :export
set custnum=5678
call :export
set custnum=9012
call :export
goto :eof
:export
sqlcmd -E -i script.sql -o %custnum%.txt -v CustNum=%custnum%
goto :eof
Copy and paste the set/call lines once for each of your 18 customers.
Instead of copy+paste, you could do something with a for loop if you have a list of the customers somewhere - output of another SQLCMD query, or just a text file. I leave that to you to figure out.

Understanding case expression in the "Where" clause

I've got this code here and you can see from my Pseudocode what I'm trying to accomplish
select *
from dbo.BenefitsForms
inner join Dependents on BenefitsForms.UserId = Dependents.BenefitsForm_UserId
inner join CoverageLevels on BenefitsForms.MedicalId = CoverageLevels.Id
where (BenefitsForms.MedicalId > 0 AND BenefitsForms.MedicalId < 13)
AND Dependents.IsSpouse = CASE when CoverageLevels.[Level] = 2 then 1
when CoverageLevels.[Level] = 3 then 0 end
when CoverageLevels.[Level] = 4 then [any, it doesnt matter] <--- my desire but it doesn't work.
What can I do to get the effect I desire in the brackets? If Coverage Level = 4 then I don't care what Dependents.IsSpouse is, I don't even need to sort by it anymore.
Assuming that isSpouse can only be 0 or 1... if CoverageLevels.Level is 4, then compare isSpouse to itself, which will always result in true:
AND Dependents.IsSpouse = CASE
when CoverageLevels.[Level] = 2 then 1
when CoverageLevels.[Level] = 3 then 0
when CoverageLevels.[Level] = 4 then Dependents.IsSpouse
END
Alternately, this can also be expressed without the CASE:
WHERE
BenefitsForms.MedicalId > 0
AND BenefitsForms.MedicalId < 13
AND (
(Dependents.IsSpouse = 1 AND CoverageLevels.[Level] = 2)
OR (Dependents.IsSpouse = 0 AND CoverageLevels.[Level] = 3)
OR CoverageLevels.[Level] = 4
)