How can I sum the same column differently depending on another column type - tsql

I have a SQL Query I want to create in Alteryx.  This query goes through an Invoicing table and sums up different charges depending on the location that is associated with it.  So each location can have different types for each column.  Below is an example:
Location FreightCharge InvoiceCharge
A FRT IVC
B FRT, CHG IVC, DTL
Using a query with a case statement worked fine when I only had one location to worry about.  Now I will potentially have hundreds.  I created a Locations table that has the types in it (the table above).  But I'm not convinced it's the right way to do this.
ultimately I would either want a SQL Statement (alteryx) that can do this from the ground up or (more likely) a workflow I can use to loop through locations which links to my reference table and automatically tallies this data.
Any ideas?
However, it would be nice if I could run this for each location, appending it to an invoice table.  
I've tried creating a reference table and joining it to my main invoicing query but I can't get it to filter by the correct data. I've considered creating a Alteryx or SSIS Package that loops through each record, however I don't need to loop through things one record at a time. Just one location at a a time.
This would go into a table like this for location A:
Select Location, InvoiceNumber, Case WHEN InvoiceType IN('FRT') THEN InvoiceAmount Else 0 End as FreightCharge --**I want this to be dynamic depending on location, Case WHEN InvoiceType IN('IVC','DTL') then InvoiceAmount Else 0 End as InvoiceCharge --**I want this to be dynamic depending on location From Invoicing Where InvoiceDate = Today
I would want an invoicing table with all locations and their summed values (how they should sum according to the reference table) all in one table.

Suppose you organize your lookup table as:
Location GroupLabel InvoiceType
A Freight FRT
A Invoice IVC
B Freight FRT
B Freight CHG
B Invoice IVC
B Invoice DTL
And it sounds like your data is something like...
Location InvoiceNumber InvoiceAmount InvoiceType
A 1 1.00 FRT
A 1 2.00 IVC
A 2 3.00 FRT
A 2 4.00 IVC
B 3 5.00 FRT
B 3 6.00 IVC
B 4 7.00 CHG
B 4 8.00 DTL
Then, I think the following would provide what you're after...
Select
i.Location
, i.InvoiceNumber
, l.GroupLabel
, Sum(i.Amount)
From
Invoicing i
Inner Join LookupTable l
on l.Location = i.Location
and l.InvoiceType = i.InvoiceType
Group By
i.Location
, i.InvoiceNumber
, l.GroupLabel
In Alteryx, it should be pretty straightforward to do the Join on both Location and InvoiceType before doing an Aggregation grouped by the three fields shown and summing InvoiceAmount.

Related

PostgreSql Group into predefined groups, where one group acts as group anything thats left

I have a database table with data similar to this.
create table DataTable {
name text,
value number
}
insert into DataTable values
('A', 1),('A', 2),('B', 3),('Other', 5),('C', 1);
I have 3 values A, B and Other.
I want to count the values so that the C get aggregated into Other
Expected output
Name | sum
A | 3
B | 3
Other | 6
I know that the result could be achieved by 2 sub queries, 1 That groups only A, B and OTher and the other that count everything that isnt A or B or Other into Other. And then agggregate these 2 subqueries together.
My question is, is there a way to do this without multiple subqueries? Reson being, the actual query in the application is a monster with multiple joins and aggregations. Repeating the same piece of code multiple times would make it very hard to maintain. So im hoping there is a clever trick.
Simple CASE might do the job:
SELECT
CASE
WHEN name != 'A' AND name != 'B' THEN 'Other'
ELSE name
END AS mapped_name,
SUM(value)
FROM DataTable
GROUP BY mapped_name
without any subquery at all.

Recursive CTE in Postgres - SUM at each parent node

I`m storing a hierarchical product adjacency list and a separate table for all the sales on those products.
Currently, I`m trying to present to the user a "Sales Report" with the total amount/sum sold per each product, and at the parent level.
In the sales table, I do not have info on the sales per group, thus, I have info available only at the level of the child. From what I have read I need to use recursive CTE, and I tried creating some queries, without any success.
Example of my dataset:
F - folders
P - products
Products table:
id
name
parentid
1
F1
NULL
2
F2
1
3
P1
2
4
P2
2
Sales table:
id
quant
sum
3
3
90
4
2
100
What I need to obtain in the report:
id
name
parentid
quant
sum
1
F1
NULL
5
190
2
F2
1
5
190
3
P1
2
3
90
4
P2
2
2
100
Logically, I understand that I need to fetch each row, and recursively go through all its children in order to SUM the quant and the sum, however I have no clue how to write it.
I`d be thankful for any guidance on where I could read more about recursive CTE, or anything that can help my situation.
Cheers!

Left join in tabular model

I have 2 tables as below.
BILLING
AccountId RatingDate Load
1280582 2018-01-04 15:20:13.000 130.000
421947 2018-01-04 11:44:58.000 176.000
1033717 2018-01-04 10:52:23.000 234.000
RATING
AccountId RatingDate RatingMethod
1280582 2018-01-04 15:20:13.000 A
421947 2018-01-04 11:44:58.000 A
1033717 2018-01-04 10:52:23.000 A
I need to create a measure in Billing table to calculate the sum of Load column. I have the SQL query to perform the same but I am not able to create the measure with the same logic.
SELECT SUM(b.Load)
FROM Billing b
LEFT JOIN Rating r
ON b.AccountId = r.AccountId
AND b.RatingDate = r.RatingDate
WHERE r.RatingMethod = 'A'
Can someone help me with the dax formula for creating the measure?
There are a few ways to approach this including
Do the left join in the query editor.
Create bridge tables or unique indexing columns to relate your two tables.
Write a measure using the LOOKUPVALUE function.
If you're doing a bunch of other stuff, you'll probably want to consider option #1 or #2, but for just this particular measure, I'll show you #3.
LoadSum = CALCULATE(SUM(Billing[Load]),
FILTER(Billing,
LOOKUPVALUE(Rating[RatingMethod],
Rating[AccountID], Billing[AccountID],
Rating[RatingDate], Billing[RatingDate])
= "A"))
The above sums over the [Load] after filtering rows where [RatingMethod] = "A" in the Rating table (and matching on the ID and date columns).
For #1, select your Rating query and click Merge Queries (Home tab).
Select the columns you want to join one (Ctrl+Click in the same order on both of them). Keep the default Left Outer Join and hit OK.
Once they're merged, you'll have a new column named Billing. Click the expand icon in the top right corner of the column and select which columns you want to expand (select Load only).
Once expanded, your table should look like this:
RATING
AccountId RatingDate RatingMethod Load
1280582 2018-01-04 15:20:13 A 130
421947 2018-01-04 11:44:58 A 176
1033717 2018-01-04 10:52:23 A 234

MicroStrategy - Dynamic Attribute with join

In our MicroStrategy 9.3 environment, we have a star schema that has multiple date dimensions. For this example, assume we have a order_fact table has two dates, order_date and ship_date and an invoice_fact table with two dates invoice_date and actual_ship_date. We have a date dimension that has "calendar" related data. We have setup each date with an alias, per the MicroStrategy Advanced Data Warehousing guide, which is MicroStrategy's recommended approach to handling role-playing dimensions.
Now for the problem. The aliased dates allow for users to create reports specific to the date that has been aliased. However, since the dates have been aliased, MicroStrategy won't combine "dates" as they appear to it to be different. Case in point, I can't easily put on a report that shows order quantities and invoice quantities by order_date and invoice_date as it results in a cross join.
The solution we have been talking about internally, is creating a new attribute called order_fact_date and an invoice_fact_date. These dates would be determined at runtime via the psuedo code below:
case when <user picked date> = 'order date'
then order_date
else ship_date end as order_fact_date
case when <user picked date> = 'invoice date'
then invoice_date
else actual_ship_date as invoice_fact_date
Our thinking was then, we could have a "general" date dimension mapped to both dates which would enable MicroStrategy to leverage the same table in the joins and thereby eliminating the cross join issue.
Clear as mud?
Edit 1: Changed "three dates" to "two dates".
if I have understood correctly your problem, you have created multiple dates attributes (with different logical meaning) and they are mapped on different aliases of the calendar table.
Until users use different a single fact table in their reports there is no problem, but when they use metrics/facts from sales and invoices you have multiplied results because "Order Date" and "Invoice Date" are different attributes.
Your SQL looks something like:
...
FROM order_fact a11
INNER JOIN invoice_fact a12
INNER JOIN lu_calendar a13
ON a11.order_date = a13.date_id
INNER JOIN lu_calendar a14
ON a12.invoice_date = a14.date_id
...
As usual there are possible solution, not all of them very straight forward.
Option 1 - Single date attribute
You mention this possibility in your question, instead of using "Order Date" and "Invoice Date", just use a single "Date" attribute and teach users to use it. You can call it "Reporting Date" or "Operation Date" if this makes the life easier for them.
The SQL you should get is something like:
...
FROM order_fact a11
INNER JOIN invoice_fact a12
ON a11.order_date = a12.invoice_date
INNER JOIN lu_calendar a13 -- Only one join
ON a11.order_date = a13.date_id -- because the date is the same
...
Option 2 - We need to keep the two date attributes!
Map "Order Date" and "Invoice Date" on the same alias of your calendar table. This is usually can cause problems in MicroStrategy, because two attributes will be joined together on the same look-up table [see later on this], but in your case this is exactly what you are looking for.
With this solution you should get an SQL like this:
...
FROM order_fact a11
INNER JOIN invoice_fact a12 -- Hey! this is again a cross join!
INNER JOIN lu_calendar a13
ON a11.order_date = a13.date_id -- Relax man, we got you covered.
AND a12.invoice_date = a13.date_id -- Yes, we do it!
...
This is nice, but it works only if you have description forms coming from the calendar table (this is not always the case with dates because the ID is usually also the actual value that you show on your reports). In case you don't have a join with the calendar lookup, you SQL will end up again with duplicated result:
...
FROM order_fact a11 -- Notice no join column between the two facts
INNER JOIN invoice_fact a12 -- and no other conditions will help to join them
...
For this reason if you want to keep the two attributes separate, beside mapping them on the same lookup, you should also:
Create an hidden attribute (let's call it "Date_on_fact") map it on the fact table and the calendar table and make it child of both "Order Date" and "Invoice Date".
Un-map the "Order Date" and "Invoice Date" from the fact tables.
The idea here is to force MicroStrategy to use always the SQL code always the calendar lookup table:
...
FROM order_fact a11
INNER JOIN invoice_fact a12 -- This is like the previous one
INNER JOIN lu_calendar a13 -- But I'm back to help you
ON a11.order_date = a13.date_id
AND a12.invoice_date = a13.date_id
...
The attribute "Date_on_fact" can actually be hidden and users don't need to put it in their reports, but MicroStrategy will use it to go from the parent attributes to the fact table.
Hope this can help you to get out from the mud.
We had a same problem.
We had to create a generic time hierarchy for this and connected 2 different invoice and order time hierarchies to the generic one.
It works like charm!

How to ignore duplicates in recordset of Crystal Reports

Say I have a result set with these values:
orderID typeofSale
A1 Sell
A1 Buy
B1 Sell
C1 Sell
The total number of orders here is 3, as A1 got divided. How can this be calculated in Crystal?
I tried looping through the orders with WhileReadingRecords; and maintaining the order ids read in an array, and then checking of the order id had already been read, thus not double counting. However, Crystal has an array limitation of 1000 records only....
I've been struggling with this. For some reason, the prev report creator wants this value in the report header, making it all the more difficult.
You can use DistinctCount
In a formula you would do:
DistinctCount({Table.Yourfield})
Or from the menu Insert > Summary then choose the field you want summarize and select Distinct Count from the Calculate this summary drop down.