create a new table from 2 other tables - pandas

If I want to merge the table with 2 other tables b,c
where table a contains columns:( Parent, Style, Ending_Date, WeekNum, Net_Requirment)
tables and calculate how much is required to make product A in a certain date.
The table should like the BOM (Bill of Material)
Can it be applied by pandas?
table b represent the demand for product A per date:
Style Date WeekNum Quantity
A 24/11/2019 0 600
A 01/12/2019 1 500
table c represent Details and quantity used to make product A:
Parent Child Q
A A1 2
A1 A11 3
A1 A12 2
so table a should be filled like this:
Parent Child Date WeekNum Net_Quantity
A A1 24/11/2019 0 1200
A1 A11 24/11/2019 0 3600
A1 A12 24/11/2019 0 2400
A A1 01/12/2019 1 1000
A1 A11 01/12/2019 1 3000
A1 A12 01/12/2019 1 2000

Welcome, in order to properly merge these tables and the rest you would have to have a common key to merge on. What you could do is add said key to each table like this:
data2 = {'Parent':['A','A1','A1'], 'Child':['A1','A11','A12'],
'Q':[2,3,2], 'Style':['A','A','A']}
df2 = pd.DataFrame(data2)
After this you can do a left join on the first table and then you can have multiple rows for the same date. So essentially this:
(notice if you do a left join, your left table will create as many duplicate rows as needed tu suffice the matching key on the right table)
data = {'Style':['A','A'], 'Date':['24/11/2019', '01/12/2019'],
'WeekNum':[0,1], 'Quantity':[600,500]}
df = pd.DataFrame(data)
mergeDf = df.merge(df2,how='left', left_on='Style', right_on='Style')
mergeDf
Then to calculate:
test['Net_Quantity'] = test.Quantity*test.Q
test.drop(['Q'], axis = 1,inplace=True)
result:
Style Date WeekNum Quantity Parent Child Net_Quantity
0 A 24/11/2019 0 600 A A1 1200
1 A 24/11/2019 0 600 A1 A11 1800
2 A 24/11/2019 0 600 A1 A12 1200
3 A 01/12/2019 1 500 A A1 1000
4 A 01/12/2019 1 500 A1 A11 1500
5 A 01/12/2019 1 500 A1 A12 1000

Related

Compare values from one column in table A and another column in table B

I need to create a NeedDate column in the expected output. I will compare the QtyShort from Table B with QtyReceive from table A.
In the expected output, if QtyShort = 0, NeedDate = MaltDueDate.
For the first row of table A, if 0 < QtyShort (in Table B) <= QtyReceive (=6), NeedDate = 10/08/2021 (DueDate from Table A).
If 6 < QtyShort <= 10 (QtyReceive), move to the second row, NeedDate = 10/22/2021 (DueDate from Table A).
If 10 < QtyShort <= 20 (QtyReceive), move to the third row, NeedDate = 02/01/2022 (DueDate from Table A).
If QtyShort > QtyReceive (=20), NeedDate = 09/09/9999.
This should continue in a loop until the last row on table B has been compared
How could we do this? Any help will be appreciated. Thank you in advance!
Table A
Item DueDate QtyReceive
A1 10/08/2021 6
A1 10/22/2021 10
A1 02/01/2022 20
Table B
Item MatlDueDate QtyShort
A1 06/01/2022 0
A1 06/02/2022 0
A1 06/03/2022 1
A1 06/04/2022 2
A1 06/05/2022 5
A1 06/06/2022 7
A1 06/07/2022 10
A1 06/08/2022 15
A1 06/09/2022 25
Expected Output:
Item MatlDueDate QtyShort NeedDate
A1 06/01/2022 0 06/01/2022
A1 06/02/2022 0 06/02/2022
A1 06/03/2022 1 10/08/2021
A1 06/04/2022 2 10/08/2021
A1 06/05/2022 5 10/08/2021
A1 06/06/2022 7 10/22/2021
A1 06/07/2022 10 10/22/2021
A1 06/08/2022 15 02/01/2022
A1 06/09/2022 25 09/09/9999
Use OUTER APPLY() operator to find the minimum DueDate from TableA that is able to fulfill the QtyShort
select b.Item, b.MatlDueDate, b.QtyShort,
NeedDate = case when b.QtyShort = 0
then b.MatlDueDate
else isnull(a.DueDate, '9999-09-09')
end
from TableB b
outer apply
(
select DueDate = min(a.DueDate)
from TableA a
where a.Item = b.Item
and a.QtyReceive >= b.QtyShort
) a
Result:
Item
MatlDueDate
QtyShort
NeedDate
A1
2022-06-01
0
2022-06-01
A1
2022-06-02
0
2022-06-02
A1
2022-06-03
1
2021-10-08
A1
2022-06-04
2
2021-10-08
A1
2022-06-05
5
2021-10-08
A1
2022-06-06
7
2021-10-22
A1
2022-06-07
10
2021-10-22
A1
2022-06-08
15
2022-02-01
A1
2022-06-09
25
9999-09-09
db<>fiddle demo

Create column based on other column but with conditions

I'm very new to SQL and I've I simply cannot work out a method for the following:
I have this table with start dates of the codes
Row Code Start Date Product
1 A1 2020-01-01 X
2 A1 2020-05-15 Y
3 A2 2020-02-02 X
4 A3 2020-01-31 Z
5 A3 2020-02-15 Y
6 A3 2020-12-31 X
Ultimately I need to be able to query another table and find out what Product a code was on a certain date, so Code A1 on 2020-01-10 was = X, but Code A1 today is = Y
I think I can work out how to use a between statement in the where clause, but I cannot work out how to Alter the table to have an End Date so it looks like this:
Row Code Start_Date Product End_Date
1 A1 2020-01-01 X 2020-05-14
2 A1 2020-05-15 Y NULL
3 A2 2020-02-02 X NULL
4 A3 2020-01-31 Z 2020-02-14
5 A3 2020-02-15 Y 2020-12-30
6 A3 2020-12-31 X NULL
Please note the database does not have an End_Date field
I think you want lead():
select t.*,
dateadd(day, -1,
lead(start_date) over (partition by code order by start_date)
) as end_date
from t;
Note: I would recommend not subtracting one day for the end date, so the end date is non-inclusive. This makes the end date the same as the next start date, which I find is easier to ensure that there are no gaps or overlaps in the data.

Why is T-SQL Returning Duplicate Rows, Join Issue I Believe

The code as written below returns the appropriate customers, lockers, units and balance. However, when I add in the commented-out code it reiterates each customer's data for each club even though each customer can only be a member of one club.
USE db1
GO
SELECT [db1].[dbo].[Customer].[CustomerNumber] AS 'Customer No.'
-- ,A. ClubID AS 'Club ID No.'
,(SELECT CONCAT (SI.Locker, '-', SI.Frequency)) AS Locker
,SI.Unit AS Unit
--,[db2].[dbo].[vueClub].Club_aka AS Club
,[db1].[dbo].[Customer_Balance].[CurrentBalance]
FROM [db1].[dbo].[Customer_Balance]
JOIN [db1].[dbo].[Customer]
ON [db1].[dbo].[Customer_Balance].POSCusNo = Customer.CustomerNumber
JOIN [SQLSrv01].[ db3].[dbo].[md_Table_1] AS D
ON D.Contract_no = [db1].[dbo].[Customer_Balance]. POSCusNo
JOIN [SQLSrv01].[ db2].[dbo].[vueSoldLockers] AS SI
ON SI.CustomerID = [db1].[dbo].[Customer].CustomerID
--JOIN [db2].[dbo].[vueClub] AS A
--ON [db1].[dbo].[Customer].SiteID = A.SiteID
WHERE [db1].[dbo].[Customer_Balance].StatusCode = '1234'
ORDER BY Customer.CustomerNumber ASC
So if I run it as is I get:
Customer No. Locker Unit Current Balance
1 315 A1 456.00
2 316 A3 1204.70
3 317 B2 335.60
4 318 B4 1500.30
But if I include the commented-out code I get:
Customer No. Club ID No Locker Unit Club Current Balance
1 4 315 A1 Tigers 456.00
1 3 315 A1 Lions 456.00
2 4 316 A3 Tigers 1204.70
2 3 316 A3 Lions 1204.70
3 4 317 B2 Tigers 335.60
3 3 317 B2 Lions 335.60
4 4 318 B4 Tigers 1500.30
4 3 318 B4 Lions 1500.30
Is it because I don't have the JOIN set up properly?
Customer No. Club ID No Locker Unit Club Current Balance
1 4 315 A1 Tigers 456.00
1 3 315 A1 Lions 456.00
You are joining customer to vueClub on SiteID. Looks like the site customer 1 is in, has 2 clubs (3, 4)

Find sequential child rows that have amounts which add up to parent row's amount

I have a table like following
ID DATE ACCT TYPE AMOUNT SEQ CHK# TRC
1 6/5/2014 1234 C 10,000 1 1001
2 6/5/2014 3333 3,000 2 123 1002
3 6/5/2014 4444 5,000 3 234 1003
4 6/5/2014 5555 2,000 4 345 1004
5 6/5/2014 2345 C 3,000 1 1007
6 6/5/2014 5555 2,500 2 255 1008
7 6/5/2014 7777 500 3 277 1009
8 6/6/2014 1234 C 5,000 1 2001
9 6/6/2014 7777 3,000 2 278 2002
10 6/6/2014 8888 2,000 3 301 2003
The rows with TYPE = C are parent rows to the child rows that follow sequentially.
The parent rows do not have CHK# and child rows do have CHK#. Each
parent row has seq# = 1 and child rows have sequential numbers. (if it
matters) From above table, row ID 1 is the parent row to the rows with
ID 2 ~ 4. The AMOUNT on the child rows add up to the parent row's
amount.
Querying for transaction for date of '6/5/2014' on account # 2345 with
the amount of 3,000 - result should be rows with ID 6 and 7.
Is such query possible using MS-SQL 2008? If so, could you let me
know?
Well, based on the data that you have, you can use the id column to find the rows that you want. First, look for the one that has the check in that amount. The look for the subsequent ids with the same group. How do you define the group? That is easy. Take the difference between id and seq. This difference is constant for the parent and child rows.
So, here is goes:
select t.*
from table t
where (t.id - t.seq) = (select t2.id - t2.seq
from table t2
where t2.type = 'C' and
t2.acct = '2345' and
t2.date = '6/5/2014'
) and
t.type is null;

How would you implement this query? Recordset or Sql

I just saw this question in an interview test I took few days back, I have the following table
Region Company Sales ratio_of_sales_in_region percentile_in_region
NA A1 1000 0.25 25
NA A2 1000 0.25 50
NA A3 1000 0.25 75
NA A4 1000 0.25 100
EU B1 2000 0.5 50
EU B2 1000 0.25 75
EU B3 1000 0.25 100
.......
I need to extract the 30th percentile company and sales for each region
the result would be
Region 30th_percentile_company 30th_percentile_sales
NA A2 (1000*0.25 + 500 * 0.05)
EU B1 2000 (as B1 accounts for more than 30%)
The query would need to check for the above conditions like does a company already account for more than 30% and also take the weight for 30 percentile sales for each region.
EDIT : I have tried to explain what percentile means by adding a new column. I was confused but I saw the result table that was asked and it made it clear as to what they meant by 30th percentile
SELECT
Region,
MIN(Company) as [30th_percentile_company], --potentially, two companies would from the same region would have the exact same percentile_in_region.
FROM
(
SELECT
Region,
MIN(percentile_in_region) as percentile_in_region
WHERE
percentile_in_region > 30
GROUP BY
Region
) a
INNER JOIN
TableName T1
ON
T1.Region = a.Region
AND T1.percentile_in_region = a.precentile_in_region
GROUP BY
Region