Joins in the MDX query - ssas

Learning MDX now a days. I have a fact table. Schema + data is following
ColumnID1 ColumnID2 Amount
O1 null 100
O2 null 200
O3 null 300
C1 null 200
C2 null 400
O5 C2 300
O4 C1 400
Query is to find the ColumnID2 not null values and add the amount of the row for that ColumnID2 Id to amount in matching ColumnId1 row. e.g
Output
ColumnID1 ColumnID2 Amount
O1 null 100
O2 null 200
O3 null 300
C1 null 200
C2 null 400
O5 C2 300 + 400
O4 C1 400 + 200
How this can be done in the MDX? Cross join is the thing coming to my mind but does not seem the right approach as it creates the cross product of the rows

Related

How can I separate a sum of widgets ordered by a vendor when I am using the select sum in a subquery? I tried group by and it still only gives total

I am trying to separate the sums in a sub query with a group by and I have three tables. I have included my current query below and tables I am using.
SELECT DISTINCT
st.stocknumber,
st.locationnumber,
P3.vendornumber,
(
SELECT SUM
( P2.orderquantity )
FROM
PH2 P2
LEFT OUTER JOIN PH1 P1 ON P1.ponumber = P2.ponumber
WHERE
p1.dateordered BETWEEN '10/13/2021'
AND '10/13/2022'
AND p2.location = 'A1'
AND p2.stocknumber = ST.stocknumber
Group BY p2.vendornumber
) As PHOrderQty
FROM
stok ST
left outer join PH2 P3 on (ST.stocknumber = P3.stocknumber)
WHERE
ST.location = 'A1'
AND ST.stocknumber IN (
'22-2552'
'JW00',
'JS20FT',
'JW090'
)
ORDER BY
stocknumber
Data looks like this
Stock Table - ST
stocknumber
location
22-2552
A1
PO Head Table - PH1
n/a
location
dateordered
ponumber
NULL
A1
10/14/2022
1
NULL
A1
10/14/2022
2
NULL
A1
10/14/2022
3
NULL
A1
10/14/2022
4
PO Details Table - PH2
stocknumber
quantityordered
vendornumber
ponumber
22-2552
3
15
1
22-2552
2
20
2
22-2552
1
15
3
22-2552
4
20
4
I keep getting back
stocknumber
location
vendornumber
PHorderQty
22-2552
A1
15
10
22-2552
A1
20
10
What I should be getting back is
stocknumber
location
vendornumber
PHorderQty
22-2552
A1
15
4
22-2552
A1
20
6
Try with the following one:
SELECT ST.stocknumber,
PH1.location,
PH2.vendornumber,
SUM(PH2.quantityordered) AS phOrderQty
FROM stock ST
INNER JOIN head PH1
ON PH1.location = PH1.location
INNER JOIN details PH2
ON ST.stocknumber = PH2.stocknumber
AND PH1.ponumber = PH2.ponumber
WHERE ST.stocknumber IN ('22-2552', 'JW00', 'JS20FT', 'JW090')
AND PH1.location = 'A1'
GROUP BY ST.stocknumber,
PH1.location,
PH2.vendornumber
Check the demo here.

How to perform Complex SQL join with multiple approximate matches and return only the first match

I am trying to perform a Left join in SQL where I need to check multiple match criteria and only retain the first match in the right table after a certain sort operation on the right table.
Below is my Left table.
(No Null values)
Date
Customer
Shop
Product
Customer_Score
1/1/2020
C1
S1
P1
2
1/2/2020
C2
S1
P2
8
1/5/2020
C3
S2
P1
6
1/6/2020
C4
S2
P2
10
1/7/2020
C1
S2
P3
2
1/8/2020
C2
S2
P4
4
And this is the right Table
(Null values allowed only in Product column)
Shop
Product
Min_Customer_Score
Valid_From
Valid_To
Percent_Discount
S1
P1
4
1/1/2020
1/5/2020
10
S1
P1
5
1/1/2020
1/5/2020
11
S1
P1
7
1/1/2020
1/5/2020
12
S1
5
1/1/2020
1/5/2020
13
S2
P1
4
1/1/2020
1/5/2020
14
S2
P2
4
1/1/2020
1/5/2020
15
S2
6
1/1/2020
1/5/2020
16
S2
9
1/1/2020
1/5/2020
17
S2
P1
4
1/6/2020
1/8/2020
18
S2
P2
4
1/6/2020
1/8/2020
19
S2
6
1/6/2020
1/8/2020
20
S2
9
1/6/2020
1/8/2020
21
I want to sort the right table first by Product(nulls at last) and then by Min_Customer_Score(ascending).
Then I want to pull the Min_Customer_Score and Discount value from first row matching below conditions:
Left.Date >= Right.Valid_From
Left.Date <= Right.Valid_To
Left.Shop = Right.Shop
Left.Product = Right.Product OR Right.Product = null
Left.Customer_Score >= Right.Min_Customer_Score
My final result should look like below.
Date
Customer
Shop
Product
Customer_Score
Min_Customer_Score
Percent_Discount
1/1/2020
C1
S1
P1
2
null
null
1/2/2020
C2
S1
P2
8
5
13
1/5/2020
C3
S2
P1
6
4
14
1/6/2020
C4
S2
P2
10
4
19
1/7/2020
C1
S2
P3
2
null
null
1/8/2020
C2
S2
P4
4
null
null
Basically, I want to find the right discount for each purchase, considering null values in the Right.Product as default discount that is applicable to all other products.
I am familiar with making Left Joins and also using Sub Queries in SQL. But I couldn't even understand where to start to do such complex queries. I have also referred to other answers which suggest using ROW_NUMBER() OVER (PARTITION BY, But couldn't work it out for this case.
Edit:
This is what I was able to work out so far.
SELECT left_table.*, right_table.Percent_Discount, right_table.Min_Customer_Score
, ROW_NUMBER() OVER (
PARTITION BY left_table.Date, left_table.Customer, left_table.Shop, left_table.Product
ORDER BY right_table.Product DESC right_table.Min_Customer_Score ASC) as row_num
LEFT JOIN right_table
ON left_table.Date >= right_table.Valid_From
AND left_table.Date <= right_table.Valid_To
AND left_table.Shop>= right_table.Shop
AND (left_table.Product = right_table.Product OR right_table.Product is NULL)
AND left_table.Customer_Score >= right_table.Min_Customer_Score
WHERE row_num = 1
But It gives me below error
ERROR: column "row_num" does not exist
LINE: WHERE row_num = 1
Use apply:
select l.*, r.*
from left l outer apply
(select top (1)
from right r
where l.Date >= r.Valid_From and
l.Date <= r.Valid_To and
l.Shop = r.Shop and
(l.Product = r.Product or r.Product = null) and
(l.Customer_Score >= r.Min_Customer_Score)
order by (case when product is not null then 1 else 2 end),
Min_Customer_Score asc
) r
Finally, I was able to solve it as below. Thanks to #iamdave for your comment
SELECT Date, Customer, Shop, Product, Customer_Score, Min_Customer_Score, Percent_Discount
FROM
(
SELECT left_table.*, right_table.Percent_Discount, right_table.Min_Customer_Score
, ROW_NUMBER() OVER (
PARTITION BY left_table.Date, left_table.Customer, left_table.Shop, left_table.Product
ORDER BY right_table.Product DESC right_table.Min_Customer_Score ASC) as row_num
LEFT JOIN right_table
ON left_table.Date >= right_table.Valid_From
AND left_table.Date <= right_table.Valid_To
AND left_table.Shop = right_table.Shop
AND (left_table.Product = right_table.Product OR right_table.Product is NULL)
AND left_table.Customer_Score >= right_table.Min_Customer_Score
) as sub_query
WHERE row_num = 1

SQL | Join two tables and get one of the tables column against any of the matching row

Table A stores site-article wise transfer/transit stock.
Table A
site article transfer_Stock transit stock
s1 a1 10 15
s1 a2 20 25
Table B has site-article-storage location wise stock
Table B
site article sloc stock
s1 a1 1000 5
s1 a1 2000 10
s1 a1 3000 15
s1 a2 1000 20
s1 a2 5000 25
I want to get total stock as for site article
Output required -
site article sloc transfer_stock transit_stock stock
s1 a1 1000 10 15 5
s1 a1 2000 0 0 10
s1 a1 3000 0 0 15
s1 a2 1000 20 25 20
s1 a2 5000 0 0 25
I want transfer stock and transit stock against any of the row of sloc.
Table A has 1 billion rows and Table B has 1.5 billion rows.
what is the optimised way to achieve this in sql.
Currently we are achieving this throguh
SELECT A.site,
A.article,
B.sloc,
case when MIN_B.sloc=B.sloc then A.transfer_stock else 0 end as transfer_stock,
case when MIN_B.sloc=B.sloc then A.transit_stock else 0 end as transit_stock,
B.stock
FROM A
LEFT OUTER JOIN B ON A.site = B.site AND A.article = B.article
LEFT OUTER JOIN (select site,article,min(sloc) from B group by site,article) MIN_B on A.site = MIN_B.site AND A.article = MIN_B.article
SELECT A.site, A.article, B.sloc, A.transfer_stock, A.transit_stock, B.stock
FROM A
LEFT JOIN B ON A.site == B.site AND A.article == B.article;

Create dynamic binary columns in sql query

I'm using presto db
I have two tables, one looks like:
table 1:
item count
p1 20
p2 10
p3 5
p4 4
p5 2
and table 2:
person lic
c1 p2
c1 p1
c2 p3
c2 p4
c2 p2
c3 p1
c4 p2
I want to return a table that looks like:
person p1 p2 p3 p4 p5
c1 1 1 0 0 0
c2 0 1 1 1 0
c3 1 0 0 0 0
c4 0 1 0 0 0
c5 0 0 0 0 0
It looks like a pivot would do, but im not sure how to account for missing values in the column and get them to be '0' in the final table
The output schema for a SQL query must be fixed. Thus, if you want a column p1 to appear in the output, it has to be listed explicitly in the query.
I'm not sure how table1 is related to the output, but you can do a pivot like this:
SELECT person
, count_if(lic = 'p1') p1
, count_if(lic = 'p2') p2
...
FROM table2
GROUP BY person
The query needs to list each p column. Depending on your application, you might be able to generate the query programmatically by first running a query to get the unique values of p.

sql server group by different columns

I have my data looking like this
Amount Officer Branch
100 S1 B1
200 S1 B2
300 S1 B3
100 S2 B1
200 S2 B2
300 S2 B3
I need another column which can show the totals by officer
Amount Officer Branch TotalByOfficer
100 S1 B1 500
200 S1 B2 500
300 S1 B3 500
100 S2 B1 900
200 S2 B2 900
600 S2 B3 900
Once i have this, I can use a having clause to filter by TotalByOfficer.
How do I accomplish such a thing.
You just need to do a SUM() OVER a PARTITION on Officer:
Select Amount,
Officer,
Branch,
Sum(Amount) Over (Partition By Officer) As TotalByOfficer
From YourTable
SELECT amount, officer, branch,
SUM(amount) OVER (PARTITION BY officer) as TotalByOfficer
FROM Table
Note, you can only use "HAVING" if you are using group by which I'm not. Use this as a sub query and add a filter, like this
SELECT *
FROM (
SELECT amount, officer, branch,
SUM(amount) OVER (PARTITION BY officer) as TotalByOfficer
FROM Table
) X
WHERE TotalByOfficer <> 500