Converting Access DB macro into PowerBI M Language - sql

I am in the process of converting an Access DB into a Power BI report. The Access Db has a macro that is run from a form using parameters, I have the same parameters in Power BI.
My current Power BI query is set up like this:
let
PDL=PDLedger,
PUL=PULedger,
Period=YTDMonth,
Yr=Year,
Source = Sql.Database("server", "database",
[Query="SELECT GBAID
, GBMCU
, GBOBJ
, [GBAN01]/100 AS P1
, [GBAN02]/100 AS P2
, [GBAN03]/100 AS P3
, [GBAN04]/100 AS P4
, [GBAN05]/100 AS P5
, [GBAN06]/100 AS P6
, [GBAN07]/100 AS P7
, [GBAN08]/100 AS P8
, [GBAN09]/100 AS P9
, [GBAN10]/100 AS P10
, [GBAN11]/100 AS P11
, [GBAN12]/100 AS P12
, case when GBLT = 'B2'
or GBLT = 'BU'
or GBLT = 'BA'
then 'B2' else GBLT end as GBLT
, GBFY
, GBCO
, GBSBLT
, GBSBL
FROM TableName
WHERE (((GBOBJ) Between '2000' And '8000')
AND ((GBLT)='B2'
Or (GBLT)='BA'
Or (GBLT)='AA'
Or (GBLT)='GP'
Or (GBLT)='" &PDL& "')
AND ((GBFY)='" &Yr& "'))
OR (((GBOBJ) Between '1000' And '1550')
AND ((GBLT)='BU'
Or (GBLT)='AU'
Or (GBLT)='" &PUL& "')
AND ((GBFY)='" &Yr& "')
AND ((GBSBLT)='S'
Or (GBSBLT)='P'))
ORDER BY GBOBJ",
CommandTimeout=#duration(0, 0, 10, 0), HierarchicalNavigation=true, MultiSubnetFailover=true])
in
Source
However, in the Access DB macro, there are these update scripts:
--REPORTS_040_ClearActual_TEMP
UPDATE Tbl_FCAST_TEMP
SET Tbl_FCAST_TEMP.P1 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=1,[P1],0) --period_2 = 2
, Tbl_FCAST_TEMP.P2 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=2,[P2],0) --period_2 = 2
, Tbl_FCAST_TEMP.P3 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=3,[P3],0) --period_2 = 2
, Tbl_FCAST_TEMP.P4 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=4,[P4],0) --period_2 = 2
, Tbl_FCAST_TEMP.P5 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=5,[P5],0) --period_2 = 2
, Tbl_FCAST_TEMP.P6 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=6,[P6],0) --period_2 = 2
, Tbl_FCAST_TEMP.P7 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=7,[P7],0) --period_2 = 2
, Tbl_FCAST_TEMP.P8 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=8,[P8],0) --period_2 = 2
, Tbl_FCAST_TEMP.P9 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=9,[P9],0) --period_2 = 2
, Tbl_FCAST_TEMP.P10 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=10,[P10],0) --period_2 = 2
, Tbl_FCAST_TEMP.P11 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=11,[P11],0) --period_2 = 2
, Tbl_FCAST_TEMP.P12 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=12,[P12],0) --period_2 = 2
WHERE (((Tbl_FCAST_TEMP.GBLT)='AA'
Or (Tbl_FCAST_TEMP.GBLT)='GP'
Or (Tbl_FCAST_TEMP.GBLT)='AU')
AND ((Tbl_FCAST_TEMP.GBFY)=[Forms]![Frm_Menu]![YEAR_2])); --17
--REPORTS_042_ClearFcast_TEMP
UPDATE Tbl_FCAST_TEMP
SET Tbl_FCAST_TEMP.P1 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=1,0,[P1])
, Tbl_FCAST_TEMP.P2 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=2,0,[P2])
, Tbl_FCAST_TEMP.P3 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=3,0,[P3])
, Tbl_FCAST_TEMP.P4 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=4,0,[P4])
, Tbl_FCAST_TEMP.P5 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=5,0,[P5])
, Tbl_FCAST_TEMP.P6 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=6,0,[P6])
, Tbl_FCAST_TEMP.P7 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=7,0,[P7])
, Tbl_FCAST_TEMP.P8 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=8,0,[P8])
, Tbl_FCAST_TEMP.P9 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=9,0,[P9])
, Tbl_FCAST_TEMP.P10 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=10,0,[P10])
, Tbl_FCAST_TEMP.P11 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=11,0,[P11])
, Tbl_FCAST_TEMP.P12 = IIf(([Forms]![Frm_Menu]![PERIOD_2]-1)>=12,0,[P12])
WHERE (((Tbl_FCAST_TEMP.GBLT)<>"AA"
And (Tbl_FCAST_TEMP.GBLT)<>"GP"
And (Tbl_FCAST_TEMP.GBLT)<>"B2"
And (Tbl_FCAST_TEMP.GBLT)<>"AU")
AND ((Tbl_FCAST_TEMP.GBFY)=[Forms]![Frm_Menu]![YEAR_2]));
The [Forms]![Frm_Menu]![YEAR_2] field is equivalent to the Yr=Year Parameter in the Power BI report, and the [Forms]![Frm_Menu]![PERIOD_2] is the same as the Period=YTDMonth parameter.
Is there a simple clean way to add these update scripts to the Power BI query?
EDIT:
I would like to update the fields P1 - P12 using M Language, in the same way as the Access DB macro update statements do.

I can think of two approaches to this.
1. Modify the query statement where you define your P columns.
, (CASE WHEN " & Yr & " >= 1 THEN [GBAN01]/100 ELSE 0 END) AS P1
, (CASE WHEN " & Yr & " >= 2 THEN [GBAN01]/100 ELSE 0 END) AS P2
[...]
, (CASE WHEN " & Yr & " >= 11 THEN [GBAN11]/100 ELSE 0 END) AS P11
, (CASE WHEN " & Yr & " >= 12 THEN [GBAN12]/100 ELSE 0 END) AS P12
2. If it needs to be done in M language, you can create custom columns with similar logic.
#"Custom 1" = Table.AddColumn(Source, "C1", each if Yr >= 1 then [P1] else 0),
#"Custom 2" = Table.AddColumn(#"Custom 1", "C2", each if Yr >= 2 then [P2] else 0),
[...]
#"Custom 11" = Table.AddColumn(#"Custom 10", "C11", each if Yr >= 11 then [P11] else 0),
#"Custom 12" = Table.AddColumn(#"Custom 11", "C12", each if Yr >= 12 then [P12] else 0),
Once those are created you can delete the original P columns and rename the C columns.
#"Removed Columns" = Table.RemoveColumns(#"Custom 12",{"P1", "P2", [...], "P11", "P12"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"C1", "P1"},{"C2", "P2"},[...],{"C11", "P11"},{"C12", "P12"}})

Related

Visual Fox Pro Word Automation

LOCAL oWord, oDocument, oRange, Lc_start, Lc_expr, Lc_ris, Ln_count, Lc_val
DIMENSION Lc_funct[1]
Lc_expr = ""
Ln_count = 1
oWord = CREATEOBJECT("Word.Application")
oWord.Visible = .T.
cFile = GETFILE()
oDoc = oWord.Documents.Add(m.cFile)
oRange = oWord.ActiveDocument.Range()
nWordCount = oRange.Words.Count
oRange.Collapse(1)
FOR nWord = 1 TO m.nWordCount-1
oRange.Expand(2)
cWord = oRange.Text
DO CASE
CASE m.cWord = "<|<"
Lc_start = .T.
Lc_Expr = ""
CASE m.cWord = ">|>"
Lc_start = .F.
Lc_funct[Ln_count] = Lc_Expr
Ln_count = Ln_count + 1
DIMENSION Lc_funct[Ln_count]
CASE m.Lc_start
Lc_expr = Lc_expr + m.cWord
OTHERWISE
*don't do anything
ENDCASE
oRange.Collapse(0)
ENDFOR
FOR i = 1 TO Ln_count-1
oRange = oWord.ActiveDocument.Range()
oRange.Find.Text = Lc_funct[i]
oRange.Find.Replacement.Text = EVALUATE(Lc_funct[i])
lFound = oRange.Find.Execute( , , , , , , , , , , 2 )
ENDFOR
FOR i = 1 TO Ln_count-1
oRange = oWord.ActiveDocument.Range()
oRange.Find.Text = "<|<"
oRange.Find.Replacement.Text = ""
lFound = oRange.Find.Execute( , , , , , , , , , , 2 )
ENDFOR
FOR i = 1 TO Ln_count-1
oRange = oWord.ActiveDocument.Range()
oRange.Find.Text = ">|>"
oRange.Find.Replacement.Text = ""
lFound = oRange.Find.Execute( , , , , , , , , , , 2 )
ENDFOR
MESSAGEBOX("DONE")
Hello everyone. I wrote this code to automate Word from Visual Fox Pro. I put between the escapes "<|<" and ">|>" some VFP code(like take some values from tables and so on). At the press of a button, the code scans all the document and, when find these escapes, evaluates the istructions between. The last two FORs eliminate the escape strings.
The code works, but I ask. There is a better way to do what I look for?
Also, if I have a table, there is a way to decide BEFORE the automation which columns I want to pass inside the Word document?

Datatables combine data from different columns into single row

Refer to the below image, how to merge all chapter into one single rows of different page number?
e.g.
Page 1 has 3 rows as there are 3 data at columns of chp 8,9,10
Page 2 has 5 rows as there are 5 data at columns of chp 8,9,1,11,12
So
how to have a single row of each page number and the all data placed at their own chp?
Basic SQL as below:
SELECT `mc_ee_page_id` as Page,
IF ( mc_ee_chp_id = 1, ( CASE
WHEN (is_marked = 0 and mk_no_mark = 1 ) THEN "Y"
WHEN (is_marked = 1 and mk_no_mark = -1) THEN "N"
WHEN (is_marked = 1 and mk_no_mark = 1 ) THEN "O" ELSE "X"
END ) , "" ) AS chp_1 ,
IF ( mc_ee_chp_id = 2, ( CASE
WHEN (is_marked = 0 and mk_no_mark = 1 ) THEN "Y"
WHEN (is_marked = 1 and mk_no_mark = -1) THEN "N"
WHEN (is_marked = 1 and mk_no_mark = 1 ) THEN "O" ELSE "X"
END ) , "" ) AS chp_2 ,
IF ( mc_ee_chp_id = 3, ( CASE
WHEN (is_marked = 0 and mk_no_mark = 1 ) THEN "Y"
WHEN (is_marked = 1 and mk_no_mark = -1) THEN "N"
WHEN (is_marked = 1 and mk_no_mark = 1 ) THEN "O" ELSE "X"
END ) , "" ) AS chp_3 ,
:
:
IF ( mc_ee_chp_id = 12, ( CASE
WHEN (is_marked = 0 and mk_no_mark = 1 ) THEN "Y"
WHEN (is_marked = 1 and mk_no_mark = -1) THEN "N"
WHEN (is_marked = 1 and mk_no_mark = 1 ) THEN "O" ELSE "X"
END ) , "" ) AS chp_12
FROM `maxcare_mc_ee_hw`
WHERE `stud_id` = '3312' AND `mc_ee_level_id` = '1'
GROUP BY mc_ee_chp_id, mc_ee_page_id
ORDER BY mc_ee_page_id asc
LIMIT 500
One way would be to GROUP the results of your SQL by making it the subquery of an outer query...
SELECT Page, MAX(chp_1) AS chp_1, MAX(chp_2) AS chp_2, MAX(chp_3) AS chp_3, MAX(chp_4) AS chp_4, MAX(chp_5) AS chp_5, MAX(chp_6) AS chp_6, MAX(chp_7) AS chp_7, MAX(chp_8) AS chp_8, MAX(chp_9) AS chp_9, MAX(chp_10) AS chp_10, MAX(chp_11) AS chp_11, MAX(chp_12) AS chp_12
FROM
(
-- *** paste your SQL in here ***
) AS indivdual_rows
GROUP BY Page
It assumes a page cannot have more than one non-blank value for the same chapter. If that is not the case, then it will only show the MAX alphabetical value.
Click here to go to SQL Fiddle to see it in action.

SQL Conditional statement with 2 variables showing unexpected results

I have a SP that i need to filter based on:
....
where
and cs.chargetype = #chargetype
AND (#chargetype = 'Q' and
(#biweeklypart = 1 and datepart(dd,cs.scheduledate) = 15)
OR
(#biweeklypart = 1 and datepart(dd,cs.scheduledate) <> 15)
)
But is not working.
What I need is that only when #chargetype = 'Q' and #biweeklypart = 1 then I have to filter by datepart(dd,cs.scheduledate) = 15, and if #chargetype = 'Q' and #biweeklypart = 2 then I have to filter by datepart(dd,cs.scheduledate) <> 15.
Any clue? I thought I was doing right.
Based on your description, you want this:
where cs.chargetype = #chargetype and
( (#chargetype = 'Q' and #biweeklypart = 1 and day(cs.scheduledate) = 15) or
(#chargetype = 'Q' and #biweeklypart = 2 and day(cs.scheduledate) <> 15) or
(#chargetype <> 'Q')
)

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.

SELECT FROM depending on a parameter in SQL

I want to obtain from a parameter, #Display the value 0, 1 or 2. When #Display = 0, I want to display all the items for which ec.IsEquipmentRelated is true. When #Display = 0, I want to display all the items for which ec.IsEquipmentRelated is false and when #Display = 2, I want to display all the items for which ec.IsEquipmentRelated is true OR false. How can I implement this in the FROM section?
ALTER PROCEDURE [dbo].[Downtime_GetNewCause_EquimentLocation]
#DisplayInactive bit = 0,
#SortOrder INT = 0,
#Diplay INT = 0
AS
-- Main Data source
SELECT ic.IncidentCauseID
, 'EquimentRelated' = COALESCE(ec.IsEquipmentRelated, 0)
, ic.NewIncidentCauseID
, ic.DisplayName
, ic.IsLegacy
, el.EquipmentLocationID
, el.ShopID
, ec.EquipmentClassID
, ec.EquipmentAbbr
, el.ClassSequenceNumber
, el.EquipmentComponent
, el.CompSequenceNumber
, ic.IsActive
FROM Downtime_IncidentCauses ic
LEFT JOIN Downtime_EquipmentLocations el ON ic.EquipmentLocationID = el.EquipmentLocationID
LEFT JOIN Downtime_EquipmentClasses ec ON el.EquipmentClassID = ec.EquipmentClassID AND
CASE WHEN #Diplay = 0 THEN ...
CASE WHEN #Diplay = 1 THEN ...
CASE WHEN #Diplay = 2 THEN ...
This should work:
INNER JOIN Downtime_EquipmentClasses ec
ON (el.EquipmentClassID = ec.EquipmentClassID)
AND ( (#Display = 0 AND ec.IsEquipmentRelated = 1)
OR (#Display = 1 AND ec.IsEquipmentRelated = 0)
OR (#Display = 2) )
Do it in a WHERE clause:
WHERE (#Display = 0 AND ec.IsEquipmentRelated = 'True')
OR (#Display = 1 AND ec.IsEquipmentRelated = 'False')
OR #Display = 2