Compare commits
No commits in common. "master" and "new_guidance" have entirely different histories.
master
...
new_guidan
127
WARP.md
127
WARP.md
@ -1,127 +0,0 @@
|
||||
# WARP.md
|
||||
|
||||
This file provides guidance to WARP (warp.dev) when working with code in this repository.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
This is a **pricing engine** that computes product pricing recommendations based on multiple data sources (target prices, historical sales, list prices). The system operates with both **SQL Server** and **PostgreSQL** implementations, providing pricing guidance through structured JSON responses.
|
||||
|
||||
### Core Components
|
||||
|
||||
**Database-First Architecture**: The system is primarily database-driven with stored procedures/functions as the main business logic layer. Each major component has both SQL Server (`.ms.sql`) and PostgreSQL (`.pg.sql`) implementations.
|
||||
|
||||
**Single Price Call Flow**: The main entry point is `single_price_call` which processes one pricing scenario through these stages:
|
||||
1. **Input enrichment** - Resolves customer/channel/tier from bill-to/ship-to codes
|
||||
2. **Historical price lookup** - Finds most recent/relevant sales from `lastpricedetail`
|
||||
3. **Target price lookup** - Gets configured target pricing from `target_prices`
|
||||
4. **Cost normalization** - Adjusts historical prices across different product data segments
|
||||
5. **List price lookup** - Retrieves volume-banded list prices from `pricelist_ranged`
|
||||
6. **Guidance logic** - Computes final recommended price using `guidance_logic`
|
||||
7. **JSON generation** - Creates structured `ui_json` for frontend consumption
|
||||
|
||||
**Multi-Database Support**: Core logic exists in parallel implementations:
|
||||
- **SQL Server**: `procs/*.ms.sql`, `tables/*.ms.sql`
|
||||
- **PostgreSQL**: `procs/*.pg.sql`, `tables/*.pg.sql`
|
||||
|
||||
## Common Development Commands
|
||||
|
||||
### Testing Individual Pricing Scenarios
|
||||
```sql
|
||||
-- SQL Server
|
||||
EXEC pricing.single_price_call
|
||||
@bill = 'GRIF0001',
|
||||
@ship = 'GRIF0001',
|
||||
@part = 'XNS0T1G3G18B096',
|
||||
@v1ds = 'v1:B..PLT..',
|
||||
@vol = 9600;
|
||||
|
||||
-- PostgreSQL
|
||||
SELECT ui_json->'data'
|
||||
FROM pricequote.single_price_call(
|
||||
'GRIF0001',
|
||||
'GRIF0001',
|
||||
'XNS0T1G3G18B096',
|
||||
'v1:B..PLT..',
|
||||
9600
|
||||
);
|
||||
```
|
||||
|
||||
### Running Test Examples
|
||||
Execute the complete example scenarios:
|
||||
```powershell
|
||||
# SQL Server examples
|
||||
sqlcmd -S server -d database -i example_usage.ms.sql
|
||||
|
||||
# PostgreSQL examples
|
||||
psql -d database -f example_usage.pg.sql
|
||||
```
|
||||
|
||||
### Database Schema Updates
|
||||
Deploy schema changes in this order:
|
||||
```powershell
|
||||
# 1. Tables first
|
||||
sqlcmd -S server -d database -i tables/target_prices.ms.sql
|
||||
sqlcmd -S server -d database -i tables/pricelist_ranged.ms.sql
|
||||
sqlcmd -S server -d database -i tables/lastpricedetail.ms.sql
|
||||
|
||||
# 2. Functions/procedures second
|
||||
sqlcmd -S server -d database -i procs/guidance_logic.ms.sql
|
||||
sqlcmd -S server -d database -i procs/single_price_call.ms.sql
|
||||
```
|
||||
|
||||
### Data Rebuilds
|
||||
Refresh core pricing data:
|
||||
```sql
|
||||
-- Rebuild price list with UOM conversions
|
||||
EXEC [script from pricelist_ranged.ms.sql]
|
||||
|
||||
-- Refresh historical price summaries
|
||||
EXEC [script from lastpricedetail.ms.sql]
|
||||
|
||||
-- Update target price configurations
|
||||
INSERT INTO pricing.target_prices SELECT * FROM remote.target_prices_view;
|
||||
```
|
||||
|
||||
## Key Data Structures
|
||||
|
||||
**Input Parameters**: All pricing calls require:
|
||||
- `bill` - Bill-to customer code
|
||||
- `ship` - Ship-to customer code
|
||||
- `part` - Product part number
|
||||
- `v1ds` - Product data segment (version 1)
|
||||
- `vol` - Volume quantity
|
||||
|
||||
**UI JSON Structure**: The output `ui_json` contains:
|
||||
- `details[]` - Array of pricing panels (History, List, Target Calculation, Guidance)
|
||||
- `data` - Raw `expl` JSON with all calculation details
|
||||
|
||||
**Product Data Segments**: Products have versioned data segments (v1ds/v0ds) that affect pricing:
|
||||
- Format: `v1:B..PLT..` (color tier, packaging, etc.)
|
||||
- Cross-segment price normalization uses target price ratios or cost ratios
|
||||
|
||||
## Database Schemas
|
||||
|
||||
**SQL Server**: Uses `pricing.*` schema
|
||||
- `pricing.single_price_call` - Main pricing procedure
|
||||
- `pricing.target_prices` - Configured target pricing rules
|
||||
- `pricing.lastpricedetail` - Historical price summaries per customer/product group
|
||||
|
||||
**PostgreSQL**: Uses `pricequote.*` schema
|
||||
- `pricequote.single_price_call()` - Main pricing function
|
||||
- `pricequote.target_prices` - Target pricing configurations
|
||||
- `pricequote.lastpricedetail` - Historical price data
|
||||
|
||||
## Key Business Logic
|
||||
|
||||
**Guidance Logic**: Located in `guidance_logic.*sql`, determines final price using precedence:
|
||||
1. Target price (if available)
|
||||
2. Last normalized price (prevents price drops)
|
||||
3. List price (as ceiling)
|
||||
|
||||
**Price Normalization**: When historical prices are from different product segments, they're adjusted using either target price ratios or cost ratios to enable fair comparison.
|
||||
|
||||
**Volume Banding**: List prices and target prices use volume ranges. The `pricelist_ranged` tables normalize all unit-of-measure to "PC" (pieces) for consistent volume comparisons.
|
||||
|
||||
## Archive Directory
|
||||
|
||||
Contains legacy TypeScript implementations and older SQL approaches. The `archive/apply_guidance.ts` shows the previous client-side pricing logic that has been moved to database stored procedures/functions.
|
@ -200,8 +200,8 @@ BEGIN
|
||||
calculated_pallets = FLOOR(q.vol / NULLIF(i.mpck, 0)),
|
||||
exact_pallets = CAST(ROUND(q.vol / NULLIF(i.mpck, 0), 5) AS NUMERIC(20,5))
|
||||
FROM @queue q
|
||||
LEFT JOIN pricing.cust bc ON bc.code = q.bill
|
||||
LEFT JOIN pricing.cust sc ON sc.code = q.ship
|
||||
LEFT JOIN rlarp.cust bc ON bc.code = q.bill
|
||||
LEFT JOIN rlarp.cust sc ON sc.code = q.ship
|
||||
LEFT JOIN CMSInterfaceIn.[CMS.CUSLG].itemm i ON i.item = q.part;
|
||||
|
||||
|
||||
@ -279,16 +279,16 @@ BEGIN
|
||||
,curstd_last = CASE WHEN last_isdiff = '' THEN q.curstd_orig ELSE COALESCE(v1l.curstdus, v0l.curstdus) END
|
||||
,futstd_last = CASE WHEN last_isdiff = '' THEN q.futstd_orig ELSE COALESCE(v1l.futstdus, v0l.futstdus) END
|
||||
FROM @queue q
|
||||
LEFT JOIN pricing.cost_v1ds v1 ON
|
||||
LEFT JOIN rlarp.cost_v1ds v1 ON
|
||||
v1.stlc = q.stlc
|
||||
AND v1.v1ds = q.v1ds
|
||||
LEFT JOIN pricing.cost_v0ds v0 ON
|
||||
LEFT JOIN rlarp.cost_v0ds v0 ON
|
||||
v0.stlc = q.stlc
|
||||
AND v0.v0ds = q.v0ds
|
||||
LEFT JOIN pricing.cost_v1ds v1l ON
|
||||
LEFT JOIN rlarp.cost_v1ds v1l ON
|
||||
v1l.stlc = q.stlc
|
||||
AND v1l.v1ds = q.last_dataseg
|
||||
LEFT JOIN pricing.cost_v0ds v0l ON
|
||||
LEFT JOIN rlarp.cost_v0ds v0l ON
|
||||
v0l.stlc = q.stlc
|
||||
AND v0l.v0ds = q.last_v0ds;
|
||||
|
||||
@ -471,21 +471,6 @@ BEGIN
|
||||
panel.detailLevel,
|
||||
JSON_QUERY(panel.details) AS details
|
||||
FROM (
|
||||
-- Cost
|
||||
SELECT
|
||||
'Cost' AS label,
|
||||
5 AS detailLevel,
|
||||
(
|
||||
SELECT
|
||||
'Current Std' AS label,
|
||||
5 AS detailLevel,
|
||||
COALESCE(q.curstd,0) AS value,
|
||||
'currency' AS type,
|
||||
'' AS note
|
||||
FOR JSON PATH
|
||||
) AS details
|
||||
|
||||
UNION ALL
|
||||
-- History Panel
|
||||
SELECT
|
||||
'History' AS label,
|
||||
@ -563,7 +548,7 @@ BEGIN
|
||||
-- Target Support Panel
|
||||
SELECT
|
||||
'Target Calculation' AS label,
|
||||
5 AS detailLevel,
|
||||
10 AS detailLevel,
|
||||
(
|
||||
SELECT * FROM (
|
||||
SELECT
|
||||
@ -596,7 +581,7 @@ BEGIN
|
||||
----------------------label------------------------------------------------
|
||||
'Target' AS label,
|
||||
----------------------detailLevel------------------------------------------
|
||||
5 AS detailLevel,
|
||||
10 AS detailLevel,
|
||||
----------------------value------------------------------------------------
|
||||
tprice AS value,
|
||||
----------------------type-------------------------------------------------
|
||||
|
@ -384,8 +384,8 @@ BEGIN
|
||||
,_approval_price
|
||||
,_approval_reason
|
||||
FROM
|
||||
pricequote.guidance_logic(_tprice, _last_price_norm, _listprice_eff, _last_date, 1.0, 1.0, 1.0) gl
|
||||
CROSS JOIN pricequote.approval_logic(_tprice, _last_price_norm, _listprice_eff, _last_date, 1.0, 1.0, 1.0) al;
|
||||
pricequote.guidance_logic(_tprice, _last_price_norm, _listprice_eff, _last_date, .95, 1.0, 1.0) gl
|
||||
CROSS JOIN pricequote.approval_logic(_tprice, _last_price_norm, _listprice_eff, _last_date, .95, 1.0, 1.0) al;
|
||||
|
||||
------------------------------------------------------------------
|
||||
-- Step 8: Build explanation JSON
|
||||
|
@ -1,275 +0,0 @@
|
||||
CREATE OR ALTER PROCEDURE pricing.rebuild_lastprice
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
SET XACT_ABORT ON; -- auto-rollback on most errors
|
||||
|
||||
BEGIN TRY
|
||||
BEGIN TRAN; -- start transaction
|
||||
--------------------------------------------------------------------------------
|
||||
-- Reset target tables
|
||||
--------------------------------------------------------------------------------
|
||||
--DROP TABLE IF EXISTS pricing.lastpricedetail;
|
||||
DELETE FROM pricing.lastpricedetail;
|
||||
DROP TABLE IF EXISTS #flagged;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Stage 1: Load cleaned input rows
|
||||
-- Filters out irrelevant quotes/orders and calculates unit prices
|
||||
--------------------------------------------------------------------------------
|
||||
WITH base AS (
|
||||
SELECT
|
||||
o."Customer" AS customer,
|
||||
o."Part Group" AS partgroup,
|
||||
RTRIM(i.V1DS) AS dataseg,
|
||||
o."Data Source" AS version,
|
||||
o."Part Code" AS part,
|
||||
o."Units" AS qty,
|
||||
CASE
|
||||
WHEN o."Units" = 0 THEN NULL
|
||||
ELSE ROUND(o.[Value USD] / NULLIF(o."Units", 0), 5)
|
||||
END AS price,
|
||||
o.[Order Date] AS odate,
|
||||
o.[Order Number] AS ordnum,
|
||||
o.[Quote Number] AS quoten
|
||||
FROM
|
||||
fanalysis.rlarp.osm_stack_pretty o
|
||||
INNER JOIN CMSInterfaceIn.[CMS.CUSLG].ITEMM i
|
||||
ON i.item = o.[Part Code]
|
||||
WHERE
|
||||
o.[Data Source] IN ('Actual', 'Quotes')
|
||||
AND o."Customer" IS NOT NULL
|
||||
AND o."Financial Statement Line" = '41010'
|
||||
AND o."Order Status" <> 'CANCELLED'
|
||||
AND o."Units" > 0
|
||||
AND o."Part Group" <> ''
|
||||
-- Optional filter for testing
|
||||
-- AND o."Customer" = 'ESBENSHADES GREENHOUSE'
|
||||
),
|
||||
--------------------------------------------------------------------------------
|
||||
-- Stage 2: Rank each row based on recency and volume rules
|
||||
-- Flags include:
|
||||
-- - rn_mrs: most recent sale
|
||||
-- - rn_mrq: most recent quote
|
||||
-- - rn_lvs: largest sale in last year
|
||||
-- - rn_lvq: largest quote in last year
|
||||
-- - rn_dss: most recent sale per dataseg
|
||||
-- - rn_dsq: most recent quote per dataseg
|
||||
--------------------------------------------------------------------------------
|
||||
ranked AS (
|
||||
SELECT
|
||||
b.*
|
||||
-- Most recent sale (Actuals only)
|
||||
,CASE WHEN b.version = 'Actual' THEN
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup
|
||||
ORDER BY b.odate DESC
|
||||
)
|
||||
END AS rn_mrs
|
||||
-- Most recent quote (Quotes only)
|
||||
,CASE WHEN b.version = 'Quotes' THEN
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup
|
||||
ORDER BY b.odate DESC
|
||||
)
|
||||
END AS rn_mrq
|
||||
-- Largest volume sale (Actuals only; last 12 months prioritized)
|
||||
,CASE WHEN b.version = 'Actual' THEN
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup
|
||||
ORDER BY
|
||||
CASE WHEN b.version = 'Actual' AND b.odate >= DATEADD(YEAR, -1, GETDATE()) THEN 1 ELSE 0 END DESC,
|
||||
b.qty DESC
|
||||
)
|
||||
END AS rn_lvs
|
||||
-- Largest volume quote (Quotes only; last 12 months prioritized)
|
||||
,CASE WHEN b.version = 'Quotes' THEN
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup
|
||||
ORDER BY
|
||||
CASE WHEN b.version = 'Quotes' AND b.odate >= DATEADD(YEAR, -1, GETDATE()) THEN 1 ELSE 0 END DESC,
|
||||
b.qty DESC
|
||||
)
|
||||
END AS rn_lvq
|
||||
,CASE WHEN b.version = 'Actual' THEN
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup, b.dataseg, b.version
|
||||
ORDER BY b.odate DESC
|
||||
)
|
||||
END AS rn_dss
|
||||
,CASE WHEN b.version = 'Quotes' THEN
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup, b.dataseg, b.version
|
||||
ORDER BY b.odate DESC
|
||||
)
|
||||
END AS rn_dsq
|
||||
FROM base b
|
||||
)
|
||||
--------------------------------------------------------------------------------
|
||||
-- Stage 2.5: Save only rows that meet any of the above criteria
|
||||
-- and annotate each with global-level flag (mrs, mrq, lvs, lvq)
|
||||
--------------------------------------------------------------------------------
|
||||
SELECT
|
||||
*,
|
||||
CASE WHEN rn_mrs = 1 THEN 'mrs' END AS f1,
|
||||
CASE WHEN rn_mrq = 1 THEN 'mrq' END AS f2,
|
||||
CASE WHEN rn_lvs = 1 THEN 'lvs' END AS f3,
|
||||
CASE WHEN rn_lvq = 1 THEN 'lvq' END AS f4,
|
||||
CASE WHEN rn_dss = 1 AND version = 'Actual' THEN 'dss' END AS f5,
|
||||
CASE WHEN rn_dsq = 1 AND version = 'Quotes' THEN 'dsq' END AS f6
|
||||
INTO #flagged
|
||||
FROM ranked
|
||||
WHERE
|
||||
rn_mrs = 1
|
||||
OR rn_mrq = 1
|
||||
OR rn_lvs = 1
|
||||
OR rn_lvq = 1
|
||||
OR (rn_dss = 1 AND version = 'Actual')
|
||||
OR (rn_dsq = 1 AND version = 'Quotes');
|
||||
|
||||
CREATE NONCLUSTERED INDEX ix_flagged_lookup
|
||||
ON #flagged(customer, partgroup, dataseg, version, part, qty, price, odate, ordnum, quoten);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Stage 3: Build JSON from flagged rows
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Step 3.1: Explode all flags from the #flagged table
|
||||
WITH exploded_flags AS (
|
||||
SELECT
|
||||
customer, partgroup, part, dataseg, version, qty, price, odate, ordnum, quoten,
|
||||
flag
|
||||
FROM #flagged
|
||||
CROSS APPLY (VALUES (f1), (f2), (f3), (f4), (f5), (f6)) AS f(flag)
|
||||
WHERE flag IS NOT NULL
|
||||
)
|
||||
--SELECT * FROM exploded_flags
|
||||
-- Step 3.2: Serialize each row into its JSON snippet
|
||||
-- Carry odate and version for deduplication in seg_pieces
|
||||
,serialized_flags AS (
|
||||
SELECT
|
||||
customer,
|
||||
partgroup,
|
||||
dataseg,
|
||||
flag,
|
||||
odate,
|
||||
version,
|
||||
CONCAT(
|
||||
'"', flag, '":',
|
||||
JSON_QUERY((
|
||||
SELECT
|
||||
version,
|
||||
dataseg AS datasegment,
|
||||
part,
|
||||
qty,
|
||||
price,
|
||||
odate,
|
||||
ordnum,
|
||||
quoten,
|
||||
flag
|
||||
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
|
||||
))
|
||||
) AS json_piece
|
||||
FROM exploded_flags
|
||||
)
|
||||
--SELECT * FROM serialized_flags
|
||||
-- Step 3.3: Collect all global-level flags (mrs, mrq, lvs, lvq)
|
||||
,flag_json AS (
|
||||
SELECT
|
||||
customer,
|
||||
partgroup,
|
||||
STRING_AGG(json_piece, ',') AS json_block
|
||||
FROM serialized_flags
|
||||
WHERE flag IN ('mrs', 'mrq', 'lvs', 'lvq')
|
||||
GROUP BY customer, partgroup
|
||||
)
|
||||
--SELECT * FROM flag_json
|
||||
-- Step 3.4: Nest dss/dsq under each dataseg
|
||||
-- Only keep the most recent dss/dsq per dataseg/version (prevents duplicate keys)
|
||||
,seg_pieces AS (
|
||||
SELECT
|
||||
customer,
|
||||
partgroup,
|
||||
dataseg,
|
||||
STRING_AGG(json_piece, ',') AS inner_json
|
||||
FROM (
|
||||
SELECT sf.*
|
||||
FROM (
|
||||
SELECT *,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY customer, partgroup, dataseg, flag
|
||||
ORDER BY odate DESC,
|
||||
CASE WHEN version = 'Actual' THEN 1 ELSE 0 END DESC
|
||||
) AS rn
|
||||
FROM serialized_flags
|
||||
WHERE flag IN ('dss', 'dsq')
|
||||
) sf
|
||||
WHERE sf.rn = 1
|
||||
) deduped
|
||||
GROUP BY customer, partgroup, dataseg
|
||||
)
|
||||
--SELECT * FROM seg_pieces
|
||||
-- Step 3.5: Wrap the inner_json under dataseg key
|
||||
,wrapped_segs AS (
|
||||
SELECT
|
||||
customer,
|
||||
partgroup,
|
||||
CONCAT(
|
||||
'"', dataseg, '": {', inner_json, '}'
|
||||
) AS json_piece
|
||||
FROM seg_pieces
|
||||
)
|
||||
-- Step 3.6: Aggregate all dataseg entries into one JSON block per customer/partgroup
|
||||
,seg_json AS (
|
||||
SELECT
|
||||
customer,
|
||||
partgroup,
|
||||
STRING_AGG(json_piece, ',') AS json_block
|
||||
FROM wrapped_segs
|
||||
GROUP BY customer, partgroup
|
||||
)
|
||||
--SELECT * FROM seg_json
|
||||
--------------------------------------------------------------------------------
|
||||
-- Stage 4: Merge flags and segment blocks into a single JSON object
|
||||
-- Write final pricing history to pricing.lastpricedetail
|
||||
--------------------------------------------------------------------------------
|
||||
INSERT INTO
|
||||
pricing.lastpricedetail
|
||||
SELECT
|
||||
COALESCE(f.customer, s.customer) AS customer,
|
||||
COALESCE(f.partgroup, s.partgroup) AS partgroup,
|
||||
CONCAT(
|
||||
'{',
|
||||
COALESCE(f.json_block, ''),
|
||||
CASE
|
||||
WHEN f.json_block IS NOT NULL AND s.json_block IS NOT NULL THEN ','
|
||||
ELSE ''
|
||||
END,
|
||||
COALESCE(s.json_block, ''),
|
||||
'}'
|
||||
) AS part_stats
|
||||
FROM flag_json f
|
||||
FULL OUTER JOIN seg_json s
|
||||
ON f.customer = s.customer AND f.partgroup = s.partgroup;
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Commit if everything succeeded
|
||||
--------------------------------------------------------------------------------
|
||||
COMMIT TRAN;
|
||||
END TRY
|
||||
BEGIN CATCH
|
||||
-- Ensure transaction is rolled back
|
||||
IF XACT_STATE() <> 0
|
||||
BEGIN
|
||||
ROLLBACK TRAN;
|
||||
END
|
||||
|
||||
-- Optional: cleanup temp table (temp table persists for session until proc end,
|
||||
-- but explicit drop is helpful if you reuse names or want to free resources)
|
||||
IF OBJECT_ID('tempdb..#flagged') IS NOT NULL
|
||||
DROP TABLE #flagged;
|
||||
|
||||
-- Rethrow the original error to the caller
|
||||
THROW;
|
||||
END CATCH;
|
||||
END;
|
@ -1 +0,0 @@
|
||||
REFRESH MATERIALIZED VIEW pricequote.lastpricedetail;
|
@ -1,6 +0,0 @@
|
||||
EXEC pricing.pricing.rebuild_lastprice;
|
||||
--2:45
|
||||
EXEC pricing.pricing.rebuild_pricelist;
|
||||
--14 secconds
|
||||
EXEC pricing.pricing.rebuild_targets;
|
||||
--12:49
|
@ -1,6 +0,0 @@
|
||||
REFRESH MATERIALIZED VIEW pricequote.lastpricedetail;
|
||||
--37 seconds
|
||||
CALL pricequote.rebuild_pricelist();
|
||||
--32 seconds
|
||||
CALL pricequote.refresh_target_prices_base();
|
||||
--45 seconds
|
@ -1,226 +0,0 @@
|
||||
CREATE OR ALTER PROCEDURE pricing.rebuild_pricelist
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
SET XACT_ABORT ON; -- auto-rollback on most errors
|
||||
|
||||
BEGIN TRY
|
||||
BEGIN TRAN;
|
||||
|
||||
DROP TABLE pricing.pricelist_ranged;
|
||||
|
||||
CREATE TABLE pricing.pricelist_ranged (
|
||||
jcplcd varchar(5) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
jcpart varchar(20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
jcunit varchar(3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
jcvoll numeric(12,5) NOT NULL,
|
||||
jcpric numeric(12,5) NOT NULL,
|
||||
vb_from float NULL,
|
||||
vb_to float NULL,
|
||||
price float NOT NULL
|
||||
);
|
||||
|
||||
CREATE NONCLUSTERED INDEX pricelist_ranged_idx ON PRICING.pricelist_ranged ( jcpart ASC , jcplcd ASC , vb_from ASC , vb_to ASC ) ;
|
||||
|
||||
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
-----------------------------------------------------------traverse unit of measure graph-----------------------------------------------------------------------
|
||||
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
-------------setup table to hold target conversions---------------------
|
||||
|
||||
|
||||
SELECT DISTINCT
|
||||
jcpart partn
|
||||
,jcunit fu
|
||||
,'PC' tu
|
||||
,cast(null as numeric) factor
|
||||
INTO
|
||||
#anchor
|
||||
FROM
|
||||
cmsinterfacein.lgdat.iprcc
|
||||
WHERE
|
||||
1=1;
|
||||
|
||||
--SELECT * FROM #anchor
|
||||
|
||||
-------pre-build punit stacked on itself with the columns flipped so you can go either direction per join---------
|
||||
SELECT
|
||||
*
|
||||
INTO
|
||||
#g
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
IHPART IHPART,
|
||||
rtrim(IHUNT1) IHUNT1,
|
||||
rtrim(IHUNT2) IHUNT2,
|
||||
IHCNV1 IHCNV1,
|
||||
IHCNV2 IHCNV2
|
||||
FROM
|
||||
CMSInterfaceIN.LGDAT.PUNIT pu
|
||||
--only deal with parts in the anchor table or the &&global parts
|
||||
INNER JOIN (
|
||||
SELECT DISTINCT partn FROM #anchor
|
||||
) items ON
|
||||
items.partn = pu.ihpart
|
||||
OR pu.ihpart = '&&GLOBAL'
|
||||
UNION
|
||||
SELECT
|
||||
IHPART IHPART,
|
||||
rtrim(IHUNT2) IHUNT1,
|
||||
rtrim(IHUNT1) IHUNT2,
|
||||
IHCNV2 IHCNV1,
|
||||
IHCNV1 IHCNV2
|
||||
FROM
|
||||
CMSInterfaceIN.LGDAT.PUNIT pu
|
||||
--only deal with parts in the anchor table or the &&global parts
|
||||
INNER JOIN (
|
||||
SELECT DISTINCT partn FROM #anchor
|
||||
) items ON
|
||||
items.partn = pu.ihpart
|
||||
OR pu.ihpart = '&&GLOBAL'
|
||||
) x ;
|
||||
|
||||
CREATE INDEX g_idx on #g(ihpart,ihunt1);
|
||||
|
||||
WITH
|
||||
--------do the expansion on all paths until the target uom is matched----------------------------------------------
|
||||
--(complains about types not matching between anchor and recursion, explicitly just casting everything)
|
||||
uom (partn, partx, lvl, mastf, mastt, xf, xt, factor, xfactor, xnum, xden, id, uom_list) AS
|
||||
(
|
||||
SELECT
|
||||
cast(partn as varchar(20)) --partn
|
||||
,cast(partn as varchar(20)) --partx
|
||||
,cast(0 as int) --lvl
|
||||
,fu --mastf
|
||||
,tu --mastt
|
||||
,cast(fu as varchar(3)) --xf
|
||||
,cast(fu as varchar(3)) --xt
|
||||
,CAST(1 AS FLOAT) --factor
|
||||
,CAST(1 AS FLOAT) --xfactor
|
||||
,CAST(1 AS FLOAT) --xnum
|
||||
,CAST(1 AS FLOAT) --xden
|
||||
,format(row_number() over (ORDER BY partn),'000000')
|
||||
,cast(trim(fu) as varchar(max))
|
||||
FROM
|
||||
#anchor
|
||||
UNION ALL
|
||||
SELECT
|
||||
cast(uom.partn as varchar(20)) --partn
|
||||
,cast(ihpart as varchar(20)) --partx
|
||||
,CAST(uom.lvl + 1 AS INT) --lvl
|
||||
,uom.mastf --mastf
|
||||
,uom.mastt --mastt
|
||||
,cast(p.ihunt1 as varchar(3)) --xf
|
||||
,cast(p.ihunt2 as varchar(3)) --xt
|
||||
,CAST(p.ihcnv2/p.ihcnv1 AS FLOAT) --factor
|
||||
,CAST(p.ihcnv2/p.ihcnv1 AS FLOAT) * uom.xfactor --xfactor
|
||||
,p.ihcnv2 * uom.xnum --xnum
|
||||
,p.ihcnv1 * uom.xden --xden
|
||||
,uom.id + '.' + format(row_number() over (PARTITION BY uom.id ORDER BY partn),'00')
|
||||
,uom.uom_list + '.' + trim(p.ihunt2)
|
||||
FROM
|
||||
uom
|
||||
INNER JOIN #g p ON
|
||||
p.ihpart IN (uom.partn,'&&GLOBAL')
|
||||
AND p.ihunt1 = uom.xt
|
||||
WHERE
|
||||
1=1
|
||||
--AND p.ihunt2 not in ('BD','BG','BU','BX','CA','CS','PA','PL','SL','C','K','DOZ','PR')
|
||||
AND p.ihunt1 <> uom.mastt
|
||||
--prevent recursion: newest joined UOM can't be in the history
|
||||
AND charindex(p.ihunt2,uom.uom_list) = 0
|
||||
)
|
||||
--SELECT COUNT(*) FROM UOM
|
||||
--------------uom is going to have multiple rows per requested conversion, need to use row_number to pick the best row------------------------------
|
||||
,sorted AS (
|
||||
SELECT
|
||||
partn, mastf from_uom, xt to_uom, xfactor factor, lvl steps, row_number() OVER (PARTITION BY partn, mastf, mastt ORDER BY lvl ASC, factor ASC) rn
|
||||
FROM
|
||||
uom
|
||||
WHERE
|
||||
xt = mastt
|
||||
)
|
||||
SELECT * INTO #uom FROM sorted WHERE rn = 1;
|
||||
--so far so good
|
||||
|
||||
drop table #anchor;
|
||||
drop table #g;
|
||||
|
||||
TRUNCATE TABLE pricing.pricelist_ranged;
|
||||
|
||||
WITH
|
||||
conv AS (
|
||||
SELECT
|
||||
p.jcplcd,
|
||||
p.jcpart,
|
||||
p.jcunit,
|
||||
p.jcvoll,
|
||||
p.jcpric,
|
||||
u.factor,
|
||||
-- Normalize volume and price to PC
|
||||
p.jcvoll * u.factor AS vol_pc,
|
||||
p.jcpric / u.factor AS price_pc
|
||||
FROM
|
||||
cmsinterfacein.lgdat.iprcc p
|
||||
INNER JOIN #uom u
|
||||
ON u.partn = p.jcpart
|
||||
AND u.from_uom = p.jcunit
|
||||
AND u.to_uom = 'PC'
|
||||
),
|
||||
sorted AS (
|
||||
SELECT
|
||||
c.*,
|
||||
ROW_NUMBER() OVER (PARTITION BY c.jcplcd, c.jcpart ORDER BY vol_pc ASC) AS rn
|
||||
FROM conv c
|
||||
),
|
||||
ranged AS (
|
||||
SELECT
|
||||
curr.jcplcd,
|
||||
curr.jcpart,
|
||||
curr.jcunit,
|
||||
curr.jcvoll,
|
||||
curr.jcpric,
|
||||
curr.vol_pc,
|
||||
curr.price_pc,
|
||||
curr.vol_pc AS vb_from,
|
||||
COALESCE(next.vol_pc, 9999999.0) AS vb_to
|
||||
FROM
|
||||
sorted curr
|
||||
LEFT JOIN sorted next
|
||||
ON curr.jcplcd = next.jcplcd
|
||||
AND curr.jcpart = next.jcpart
|
||||
AND curr.rn + 1 = next.rn
|
||||
)
|
||||
INSERT INTO
|
||||
pricing.pricelist_ranged
|
||||
SELECT
|
||||
RTRIM(jcplcd) jcplcd,
|
||||
RTRIM(jcpart) jcpart,
|
||||
jcunit,
|
||||
jcvoll,
|
||||
jcpric,
|
||||
vb_from,
|
||||
vb_to,
|
||||
price_pc AS price
|
||||
FROM
|
||||
ranged;
|
||||
|
||||
--CREATE INDEX pricelist_ranged_idx ON pricing.pricelist_ranged(jcpart, jcplcd, vb_from, vb_to);
|
||||
|
||||
COMMIT TRAN;
|
||||
END TRY
|
||||
BEGIN CATCH
|
||||
-- Ensure transaction is rolled back
|
||||
IF XACT_STATE() <> 0
|
||||
BEGIN
|
||||
ROLLBACK TRAN;
|
||||
END
|
||||
|
||||
IF OBJECT_ID('tempdb..#anchor') IS NOT NULL DROP TABLE #anchor;
|
||||
IF OBJECT_ID('tempdb..#g') IS NOT NULL DROP TABLE #g;
|
||||
IF OBJECT_ID('tempdb..#uom') IS NOT NULL DROP TABLE #uom;
|
||||
|
||||
-- Re-throw original error
|
||||
THROW;
|
||||
END CATCH;
|
||||
END;
|
@ -1,108 +0,0 @@
|
||||
CREATE OR REPLACE PROCEDURE pricequote.rebuild_pricelist()
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
|
||||
DROP TABLE IF EXISTS uomc;
|
||||
|
||||
CREATE TEMP TABLE uomc AS (
|
||||
WITH
|
||||
uom AS (
|
||||
SELECT
|
||||
uom.p part
|
||||
,uom.f fu
|
||||
,uom.t tu
|
||||
,uom.nm/uom.dm conv
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
jsonb_agg(row_to_json(d)::jsonb) jdoc
|
||||
FROM
|
||||
(
|
||||
select distinct
|
||||
jcpart partn
|
||||
, jcunit fu
|
||||
, 'PC' tu
|
||||
from
|
||||
lgdat.iprcc
|
||||
WHERE
|
||||
jcpart <> ''
|
||||
) d
|
||||
) c
|
||||
JOIN LATERAL rlarp.uom_array(c.jdoc) uom ON TRUE
|
||||
)
|
||||
SELECT * FROM uom
|
||||
) WITH DATA;
|
||||
|
||||
CREATE INDEX uom_idx ON uomc (part, fu, tu);
|
||||
|
||||
|
||||
-- Clear the output table
|
||||
TRUNCATE TABLE pricequote.pricelist_ranged;
|
||||
|
||||
--DROP TABLE pricequote.pricelist_ranged;
|
||||
|
||||
-- Compute normalized volume/price and ranges
|
||||
--CREATE TABLE pricequote.pricelist_ranged AS (
|
||||
WITH
|
||||
conv AS (
|
||||
SELECT
|
||||
p.jcplcd,
|
||||
p.jcpart,
|
||||
p.jcunit,
|
||||
p.jcvoll,
|
||||
p.jcpric,
|
||||
u.conv,
|
||||
(p.jcvoll * u.conv) AS vol_pc,
|
||||
(p.jcpric / NULLIF(u.conv, 0)) AS price_pc
|
||||
FROM
|
||||
lgdat.iprcc p
|
||||
INNER JOIN uomc u
|
||||
ON u.part = p.jcpart
|
||||
AND u.fu = p.jcunit
|
||||
AND u.tu = 'PC'
|
||||
),
|
||||
--SELECT * FROM conv LIMIT 1000
|
||||
sorted AS (
|
||||
SELECT
|
||||
*,
|
||||
ROW_NUMBER() OVER (PARTITION BY jcplcd, jcpart ORDER BY vol_pc ASC) AS rn
|
||||
FROM conv
|
||||
),
|
||||
ranged AS (
|
||||
SELECT
|
||||
curr.jcplcd,
|
||||
curr.jcpart,
|
||||
curr.jcunit,
|
||||
curr.jcvoll,
|
||||
curr.jcpric,
|
||||
curr.vol_pc,
|
||||
curr.price_pc price,
|
||||
curr.vol_pc AS vb_from,
|
||||
COALESCE(next.vol_pc, 9999999.0) AS vb_to
|
||||
FROM
|
||||
sorted curr
|
||||
LEFT JOIN sorted next
|
||||
ON curr.jcplcd = next.jcplcd
|
||||
AND curr.jcpart = next.jcpart
|
||||
AND curr.rn + 1 = next.rn
|
||||
)
|
||||
--SELECT * FROM ranged
|
||||
INSERT INTO pricequote.pricelist_ranged (
|
||||
jcplcd, jcpart, jcunit, jcvoll, jcpric, vb_from, vb_to, price
|
||||
)
|
||||
SELECT
|
||||
jcplcd,
|
||||
jcpart,
|
||||
jcunit,
|
||||
jcvoll,
|
||||
jcpric,
|
||||
vb_from,
|
||||
vb_to,
|
||||
price
|
||||
FROM ranged;
|
||||
|
||||
END;
|
||||
$$;
|
||||
|
||||
--CREATE INDEX pricelist_ranged_idx ON pricequote.pricelist_ranged ( jcpart ASC , jcplcd ASC , vb_from ASC , vb_to ASC ) ;
|
@ -1,42 +0,0 @@
|
||||
CREATE OR ALTER PROCEDURE pricing.rebuild_targets
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
SET XACT_ABORT ON; -- auto-rollback on most runtime errors
|
||||
|
||||
BEGIN TRY
|
||||
BEGIN TRAN;
|
||||
|
||||
DELETE FROM pricing.target_prices;
|
||||
|
||||
INSERT INTO
|
||||
pricing.target_prices
|
||||
SELECT
|
||||
stlc,
|
||||
ds,
|
||||
chan,
|
||||
tier,
|
||||
vol,
|
||||
-- Extract lower bound: text between '[' and ','
|
||||
TRY_CAST(SUBSTRING(vol, 2, CHARINDEX(',', vol) - 2) AS INT) AS lower_bound,
|
||||
-- Extract upper bound: text between ',' and ')'
|
||||
CASE
|
||||
WHEN RIGHT(vol, 2) = ',)' THEN NULL
|
||||
ELSE TRY_CAST(SUBSTRING(vol, CHARINDEX(',', vol) + 1, LEN(vol) - CHARINDEX(',', vol) - 1) AS INT)
|
||||
END AS upper_bound,
|
||||
price,
|
||||
math
|
||||
FROM
|
||||
usmidsap02.ubm.pricequote.target_prices_view;
|
||||
|
||||
COMMIT TRAN;
|
||||
|
||||
END TRY
|
||||
BEGIN CATCH
|
||||
IF XACT_STATE() <> 0
|
||||
ROLLBACK TRAN;
|
||||
|
||||
-- Rethrow original error
|
||||
THROW;
|
||||
END CATCH;
|
||||
END
|
@ -1,28 +0,0 @@
|
||||
CREATE OR REPLACE PROCEDURE pricequote.refresh_target_prices_base()
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
DELETE FROM pricequote.target_prices_base;
|
||||
|
||||
WITH expand AS (
|
||||
SELECT
|
||||
c.compset,
|
||||
c.stlc,
|
||||
c.floor,
|
||||
b.ds,
|
||||
b.chan,
|
||||
b.tier,
|
||||
b.vol,
|
||||
b.val,
|
||||
b.price,
|
||||
b.math AS math
|
||||
FROM pricequote.core_target c
|
||||
LEFT JOIN LATERAL pricequote.build_pricing_path_base(
|
||||
c.options || jsonb_build_object('entity','Anchor','attr',c.stlc,'val',c.floor,'func','Price')
|
||||
) AS b
|
||||
ON b.lastflag
|
||||
)
|
||||
INSERT INTO pricequote.target_prices_base
|
||||
SELECT * FROM expand;
|
||||
END;
|
||||
$$;
|
@ -1,66 +0,0 @@
|
||||
CREATE OR ALTER PROCEDURE pricing.sync_external
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON;
|
||||
SET XACT_ABORT ON; -- causes runtime errors to auto-rollback
|
||||
|
||||
BEGIN TRY
|
||||
|
||||
BEGIN TRAN;
|
||||
-- Refresh pricing.ffcret
|
||||
TRUNCATE TABLE pricing.ffcret;
|
||||
INSERT INTO pricing.ffcret
|
||||
SELECT *
|
||||
FROM fanalysis.rlarp.ffcret;
|
||||
|
||||
-- Refresh pricing.ffterr
|
||||
TRUNCATE TABLE pricing.ffterr;
|
||||
INSERT INTO pricing.ffterr
|
||||
SELECT *
|
||||
FROM fanalysis.rlarp.ffterr;
|
||||
|
||||
-- Refresh pricing.gld
|
||||
TRUNCATE TABLE pricing.gld;
|
||||
INSERT INTO pricing.gld
|
||||
SELECT *
|
||||
FROM fanalysis.rlarp.gld;
|
||||
|
||||
-- Refresh pricing.qrh
|
||||
TRUNCATE TABLE pricing.qrh;
|
||||
INSERT INTO pricing.qrh
|
||||
SELECT *
|
||||
FROM fanalysis.rlarp.qrh;
|
||||
|
||||
-- Refresh pricing.sach
|
||||
TRUNCATE TABLE pricing.sach;
|
||||
INSERT INTO pricing.sach
|
||||
SELECT *
|
||||
FROM fanalysis.lgdat.sach;
|
||||
|
||||
COMMIT TRAN;
|
||||
|
||||
-- rebuild last price
|
||||
EXEC pricing.rebuild_lastprice;
|
||||
|
||||
-- rebuild ranged price list
|
||||
EXEC pricing.rebuild_pricelist;
|
||||
|
||||
-- rebuild target prices
|
||||
EXEC pricing.rebuild_targets;
|
||||
|
||||
END TRY
|
||||
|
||||
BEGIN CATCH
|
||||
-- Rollback if any error
|
||||
IF XACT_STATE() <> 0
|
||||
ROLLBACK TRAN;
|
||||
|
||||
-- rethrow original error with context
|
||||
DECLARE @ErrMsg NVARCHAR(4000) = ERROR_MESSAGE();
|
||||
DECLARE @ErrSec NVARCHAR(200) = ERROR_SEVERITY();
|
||||
DECLARE @ErrState INT = ERROR_STATE();
|
||||
RAISERROR('refresh_pricing_tables failed: %s', 16, 1, @ErrMsg);
|
||||
THROW; -- rethrow original error for callers to handle
|
||||
END CATCH;
|
||||
|
||||
END
|
@ -1,28 +0,0 @@
|
||||
CREATE OR ALTER VIEW pricing.arcstx AS
|
||||
SELECT
|
||||
v6part PART,
|
||||
v6plnt plnt,
|
||||
v6stat stat,
|
||||
v6rpln rpln,
|
||||
v6unti unit,
|
||||
COALESCE(cnsdat, cosdat, y3sdat) sdate,
|
||||
COALESCE(cnstcs,costcs, y3stcs) std,
|
||||
COALESCE(cnmats,costcs,y3smat + y3soc + y3sshc) mat,
|
||||
COALESCE(cnlabs,y3slab,0) lab,
|
||||
COALESCE(cnbrvs,y3svbr,0) var,
|
||||
COALESCE(cnbrfs,y3sfbr,0) fix,
|
||||
COALESCE(cnstoc,y3sotc,0) oth
|
||||
FROM
|
||||
CMSInterfaceIN.lgdat.stka
|
||||
LEFT OUTER JOIN CMSInterfaceIN.ARCHIVE.ftcstm_2510 ftcstm ON
|
||||
cnpart = v6part
|
||||
AND cnplnt = v6plnt
|
||||
LEFT OUTER JOIN CMSInterfaceIN.ARCHIVE.ftcstp_2510 ftcstp ON
|
||||
copart = v6part
|
||||
AND coplnt = v6plnt
|
||||
LEFT OUTER JOIN CMSInterfaceIN.ARCHIVE.ftcstr_2510 ftcstr ON
|
||||
y3part = v6part
|
||||
AND y3plnt = v6plnt
|
||||
WHERE
|
||||
v6plnt IN ('152','154','155','112','113');
|
||||
|
@ -1,85 +0,0 @@
|
||||
DROP TABLE pricing.cost_v1ds
|
||||
DROP TABLE pricing.cost_v0ds
|
||||
|
||||
-- Final tables (one-time create)
|
||||
CREATE TABLE pricing.cost_v1ds (
|
||||
stlc varchar(50) NOT NULL,
|
||||
v1ds varchar(50) NOT NULL,
|
||||
curstdus decimal(19,6) NULL,
|
||||
futstdus decimal(19,6) NULL,
|
||||
CONSTRAINT PK_cost_v1ds PRIMARY KEY (stlc, v1ds)
|
||||
);
|
||||
|
||||
CREATE INDEX IX_cost_v1ds_cur ON pricing.cost_v1ds(stlc, v1ds, curstdus);
|
||||
|
||||
CREATE TABLE pricing.cost_v0ds (
|
||||
stlc varchar(50) NOT NULL,
|
||||
v0ds varchar(50) NOT NULL,
|
||||
curstdus decimal(19,6) NULL,
|
||||
futstdus decimal(19,6) NULL,
|
||||
CONSTRAINT PK_cost_v0ds PRIMARY KEY (stlc, v0ds)
|
||||
);
|
||||
|
||||
CREATE INDEX IX_cost_v0ds_cur ON pricing.cost_v0ds(stlc, v0ds, curstdus);
|
||||
|
||||
CREATE OR ALTER PROCEDURE pricing.refresh_cost_rollups
|
||||
AS
|
||||
BEGIN
|
||||
DELETE FROM pricing.cost_v1ds;
|
||||
|
||||
INSERT INTO
|
||||
pricing.cost_v1ds
|
||||
SELECT
|
||||
trim(stlc) stlc
|
||||
,trim(v1ds) v1ds
|
||||
,avg(curstdus) curstdus
|
||||
,avg(futstdus) futstdus
|
||||
FROM
|
||||
CMSInterfaceIN.[CMS.CUSLG].ITEMM i
|
||||
LEFT OUTER JOIN pricing.arcstx a ON
|
||||
a.part = i.item
|
||||
AND a.plnt = i.dplt
|
||||
LEFT OUTER JOIN pricing.plpr p ON
|
||||
p.plnt = i.dplt
|
||||
LEFT OUTER JOIN pricing.ffcret x ON
|
||||
x.fcur = p.curr
|
||||
AND x.tcur = 'US'
|
||||
AND x.perd = p.ic
|
||||
AND x.rtyp = 'ME'
|
||||
WHERE
|
||||
aplnt <> 'I'
|
||||
AND stlc <> ''
|
||||
AND substring(glec,1,1) <= '1'
|
||||
GROUP BY
|
||||
trim(stlc)
|
||||
,trim(v1ds);
|
||||
|
||||
DELETE FROM pricing.cost_v0ds
|
||||
|
||||
INSERT INTO
|
||||
pricing.cost_v0ds
|
||||
SELECT
|
||||
trim(stlc) stlc
|
||||
,trim(colgrp)+trim(substring(branding,1,1)) v0ds
|
||||
,avg(curstdus) curstdus
|
||||
,avg(futstdus) futstdus
|
||||
FROM
|
||||
CMSInterfaceIN.[CMS.CUSLG].ITEMM i
|
||||
LEFT OUTER JOIN pricing.arcstx a ON
|
||||
a.part = i.item
|
||||
AND a.plnt = i.dplt
|
||||
LEFT OUTER JOIN pricing.plpr p ON
|
||||
p.plnt = i.dplt
|
||||
LEFT OUTER JOIN pricing.ffcret x ON
|
||||
x.fcur = p.curr
|
||||
AND x.tcur = 'US'
|
||||
AND x.perd = p.ic
|
||||
AND x.rtyp = 'ME'
|
||||
WHERE
|
||||
aplnt <> 'I'
|
||||
AND stlc <> ''
|
||||
AND substring(glec,1,1) <= '1'
|
||||
GROUP BY
|
||||
trim(stlc)
|
||||
,trim(colgrp)+trim(substring(branding,1,1));
|
||||
END
|
@ -1,54 +0,0 @@
|
||||
CREATE OR ALTER VIEW pricing.cust AS
|
||||
SELECT
|
||||
bvcust code,
|
||||
bvbill default_billto,
|
||||
bvname descr,
|
||||
CASE WHEN bvadr6 = '' THEN bvname ELSE bvadr6 END dba,
|
||||
bvctry country,
|
||||
bvprcd province,
|
||||
bvcity city,
|
||||
bvcomp remit_to,
|
||||
bvclas cclass,
|
||||
bvstat status,
|
||||
bvtype ctype,
|
||||
RTRIM(bvschl) plevel,
|
||||
s.bk7des3 folder,
|
||||
-- pl.lists lists,
|
||||
dr.repp default_rep,
|
||||
rr.repp retail_rep,
|
||||
gr.repp inside_rep,
|
||||
nr.repp keyaccount_rep,
|
||||
u.mfresp tier
|
||||
FROM
|
||||
cmsinterfacein.lgdat.cust c
|
||||
LEFT OUTER JOIN cmsinterfacein.lgpgm.usrcust ON
|
||||
cucust = bvcust
|
||||
LEFT OUTER JOIN pricing.repc dr ON
|
||||
dr.rcode = bvsalm
|
||||
LEFT OUTER JOIN pricing.repc rr ON
|
||||
rr.rcode = currep
|
||||
LEFT OUTER JOIN pricing.repc gr ON
|
||||
gr.rcode = cugrep
|
||||
LEFT OUTER JOIN pricing.repc nr ON
|
||||
nr.rcode = cunrep
|
||||
LEFT OUTER JOIN pricing.sach s ON
|
||||
s.bk7code = c.bvschl
|
||||
LEFT OUTER JOIN pricing.ffterr t ON
|
||||
t.prov = bvprcd
|
||||
AND t.ctry = bvctry
|
||||
LEFT OUTER JOIN pricing.ffcret x ON
|
||||
x.fcur = c.bvcurr
|
||||
AND x.tcur = 'US'
|
||||
AND x.perd = (SELECT fspr FROM pricing.gld WHERE GETDATE() BETWEEN sdat AND edat)
|
||||
AND x.rtyp = 'MA'
|
||||
LEFT OUTER JOIN cmsinterfacein.lgdat.usrc u ON
|
||||
u.mfsrce = 'MN'
|
||||
AND u.mfent# = 12
|
||||
AND u.mfkey2 = c.bvcust
|
||||
-- LEFT OUTER JOIN (
|
||||
-- SELECT jbplvl, STRING_AGG(JBPLCD, ', ') AS lists
|
||||
-- FROM CMSinterfacein.[CMS.CUSLG].iprcbhc
|
||||
-- GROUP BY jbplvl
|
||||
-- ) AS pl ON
|
||||
-- pl.jbplvl = c.bvschl
|
||||
-- WHERE CASE WHEN bvadr6 = '' THEN bvname ELSE bvadr6 END = 'GRIFFIN'
|
@ -1 +0,0 @@
|
||||
SELECT * INTO pricing.ffcret FROM fanalysis.rlarp.ffcret
|
@ -1 +0,0 @@
|
||||
SELECT * INTO pricing.ffterr FROM fanalysis.rlarp.ffterr
|
@ -1 +0,0 @@
|
||||
SELECT * INTO pricing.gld FROM fanalysis.rlarp.gld
|
@ -1,7 +1,237 @@
|
||||
CREATE TABLE pricing.lastpricedetail (
|
||||
customer varchar(255),
|
||||
partgroup varchar(10),
|
||||
part_stats nvarchar(MAX)
|
||||
);
|
||||
--------------------------------------------------------------------------------
|
||||
-- Reset target tables
|
||||
--------------------------------------------------------------------------------
|
||||
--DROP TABLE IF EXISTS pricing.lastpricedetail;
|
||||
DELETE FROM pricing.lastpricedetail;
|
||||
DROP TABLE IF EXISTS #flagged;
|
||||
|
||||
CREATE UNIQUE NONCLUSTERED INDEX lastprice_cust_partgroup ON pricing.lastpricedetail ( customer ASC , partgroup ASC );
|
||||
--------------------------------------------------------------------------------
|
||||
-- Stage 1: Load cleaned input rows
|
||||
-- Filters out irrelevant quotes/orders and calculates unit prices
|
||||
--------------------------------------------------------------------------------
|
||||
WITH base AS (
|
||||
SELECT
|
||||
o."Customer" AS customer,
|
||||
o."Part Group" AS partgroup,
|
||||
RTRIM(i.V1DS) AS dataseg,
|
||||
o."Data Source" AS version,
|
||||
o."Part Code" AS part,
|
||||
o."Units" AS qty,
|
||||
CASE
|
||||
WHEN o."Units" = 0 THEN NULL
|
||||
ELSE ROUND(o.[Value USD] / NULLIF(o."Units", 0), 5)
|
||||
END AS price,
|
||||
o.[Order Date] AS odate,
|
||||
o.[Order Number] AS ordnum,
|
||||
o.[Quote Number] AS quoten
|
||||
FROM
|
||||
rlarp.osm_stack_pretty o
|
||||
INNER JOIN CMSInterfaceIn.[CMS.CUSLG].ITEMM i
|
||||
ON i.item = o.[Part Code]
|
||||
WHERE
|
||||
o.[Data Source] IN ('Actual', 'Quotes')
|
||||
AND o."Customer" IS NOT NULL
|
||||
AND o."Financial Statement Line" = '41010'
|
||||
AND o."Order Status" <> 'CANCELLED'
|
||||
AND o."Units" > 0
|
||||
AND o."Part Group" <> ''
|
||||
-- Optional filter for testing
|
||||
-- AND o."Customer" = 'ESBENSHADES GREENHOUSE'
|
||||
),
|
||||
--------------------------------------------------------------------------------
|
||||
-- Stage 2: Rank each row based on recency and volume rules
|
||||
-- Flags include:
|
||||
-- - rn_mrs: most recent sale
|
||||
-- - rn_mrq: most recent quote
|
||||
-- - rn_lvs: largest sale in last year
|
||||
-- - rn_lvq: largest quote in last year
|
||||
-- - rn_dss: most recent sale per dataseg
|
||||
-- - rn_dsq: most recent quote per dataseg
|
||||
--------------------------------------------------------------------------------
|
||||
ranked AS (
|
||||
SELECT
|
||||
b.*
|
||||
-- Most recent sale
|
||||
,ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup
|
||||
ORDER BY CASE WHEN b.version = 'Actual' THEN b.odate ELSE NULL END DESC
|
||||
) AS rn_mrs
|
||||
-- Most recent quote
|
||||
,ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup
|
||||
ORDER BY CASE WHEN b.version = 'Quotes' THEN b.odate ELSE NULL END DESC
|
||||
) AS rn_mrq
|
||||
-- Largest volume sale (last 12 months)
|
||||
,ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup
|
||||
ORDER BY CASE
|
||||
WHEN b.version = 'Actual' AND b.odate >= DATEADD(YEAR, -1, GETDATE())
|
||||
THEN b.qty ELSE NULL
|
||||
END DESC
|
||||
) AS rn_lvs
|
||||
-- Largest volume quote (last 12 months)
|
||||
,ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup
|
||||
ORDER BY CASE
|
||||
WHEN b.version = 'Quotes' AND b.odate >= DATEADD(YEAR, -1, GETDATE())
|
||||
THEN b.qty ELSE NULL
|
||||
END DESC
|
||||
) AS rn_lvq
|
||||
-- Most recent sale per data segment
|
||||
,ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup, b.dataseg, b.version
|
||||
ORDER BY CASE WHEN b.version = 'Actual' THEN b.odate ELSE NULL END DESC
|
||||
) AS rn_dss
|
||||
-- Most recent quote per data segment
|
||||
,ROW_NUMBER() OVER (
|
||||
PARTITION BY b.customer, b.partgroup, b.dataseg, b.version
|
||||
ORDER BY CASE WHEN b.version = 'Quotes' THEN b.odate ELSE NULL END DESC
|
||||
) AS rn_dsq
|
||||
FROM base b
|
||||
)
|
||||
--------------------------------------------------------------------------------
|
||||
-- Stage 2.5: Save only rows that meet any of the above criteria
|
||||
-- and annotate each with global-level flag (mrs, mrq, lvs, lvq)
|
||||
--------------------------------------------------------------------------------
|
||||
SELECT
|
||||
*,
|
||||
CASE WHEN rn_mrs = 1 THEN 'mrs' END AS f1,
|
||||
CASE WHEN rn_mrq = 1 THEN 'mrq' END AS f2,
|
||||
CASE WHEN rn_lvs = 1 THEN 'lvs' END AS f3,
|
||||
CASE WHEN rn_lvq = 1 THEN 'lvq' END AS f4,
|
||||
CASE WHEN rn_dss = 1 AND version = 'Actual' THEN 'dss' END AS f5,
|
||||
CASE WHEN rn_dsq = 1 AND version = 'Quotes' THEN 'dsq' END AS f6
|
||||
INTO #flagged
|
||||
FROM ranked
|
||||
WHERE
|
||||
rn_mrs = 1
|
||||
OR rn_mrq = 1
|
||||
OR rn_lvs = 1
|
||||
OR rn_lvq = 1
|
||||
OR (rn_dss = 1 AND version = 'Actual')
|
||||
OR (rn_dsq = 1 AND version = 'Quotes');
|
||||
|
||||
CREATE NONCLUSTERED INDEX ix_flagged_lookup
|
||||
ON #flagged(customer, partgroup, dataseg, version, part, qty, price, odate, ordnum, quoten);
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Stage 3: Build JSON from flagged rows
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Step 3.1: Explode all flags from the #flagged table
|
||||
WITH exploded_flags AS (
|
||||
SELECT
|
||||
customer, partgroup, part, dataseg, version, part, qty, price, odate, ordnum, quoten,
|
||||
flag
|
||||
FROM #flagged
|
||||
CROSS APPLY (VALUES (f1), (f2), (f3), (f4), (f5), (f6)) AS f(flag)
|
||||
WHERE flag IS NOT NULL
|
||||
)
|
||||
--SELECT * FROM exploded_flags
|
||||
-- Step 3.2: Serialize each row into its JSON snippet
|
||||
-- Carry odate and version for deduplication in seg_pieces
|
||||
,serialized_flags AS (
|
||||
SELECT
|
||||
customer,
|
||||
partgroup,
|
||||
dataseg,
|
||||
flag,
|
||||
odate,
|
||||
version,
|
||||
CONCAT(
|
||||
'"', flag, '":',
|
||||
JSON_QUERY((
|
||||
SELECT
|
||||
version,
|
||||
dataseg AS datasegment,
|
||||
part,
|
||||
qty,
|
||||
price,
|
||||
odate,
|
||||
ordnum,
|
||||
quoten,
|
||||
flag
|
||||
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
|
||||
))
|
||||
) AS json_piece
|
||||
FROM exploded_flags
|
||||
)
|
||||
--SELECT * FROM serialized_flags
|
||||
-- Step 3.3: Collect all global-level flags (mrs, mrq, lvs, lvq)
|
||||
,flag_json AS (
|
||||
SELECT
|
||||
customer,
|
||||
partgroup,
|
||||
STRING_AGG(json_piece, ',') AS json_block
|
||||
FROM serialized_flags
|
||||
WHERE flag IN ('mrs', 'mrq', 'lvs', 'lvq')
|
||||
GROUP BY customer, partgroup
|
||||
)
|
||||
--SELECT * FROM flag_json
|
||||
-- Step 3.4: Nest dss/dsq under each dataseg
|
||||
-- Only keep the most recent dss/dsq per dataseg/version (prevents duplicate keys)
|
||||
,seg_pieces AS (
|
||||
SELECT
|
||||
customer,
|
||||
partgroup,
|
||||
dataseg,
|
||||
STRING_AGG(json_piece, ',') AS inner_json
|
||||
FROM (
|
||||
SELECT sf.*
|
||||
FROM (
|
||||
SELECT *,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY customer, partgroup, dataseg, flag
|
||||
ORDER BY odate DESC,
|
||||
CASE WHEN version = 'Actual' THEN 1 ELSE 0 END DESC
|
||||
) AS rn
|
||||
FROM serialized_flags
|
||||
WHERE flag IN ('dss', 'dsq')
|
||||
) sf
|
||||
WHERE sf.rn = 1
|
||||
) deduped
|
||||
GROUP BY customer, partgroup, dataseg
|
||||
)
|
||||
--SELECT * FROM seg_pieces
|
||||
-- Step 3.5: Wrap the inner_json under dataseg key
|
||||
,wrapped_segs AS (
|
||||
SELECT
|
||||
customer,
|
||||
partgroup,
|
||||
CONCAT(
|
||||
'"', dataseg, '": {', inner_json, '}'
|
||||
) AS json_piece
|
||||
FROM seg_pieces
|
||||
)
|
||||
-- Step 3.6: Aggregate all dataseg entries into one JSON block per customer/partgroup
|
||||
,seg_json AS (
|
||||
SELECT
|
||||
customer,
|
||||
partgroup,
|
||||
STRING_AGG(json_piece, ',') AS json_block
|
||||
FROM wrapped_segs
|
||||
GROUP BY customer, partgroup
|
||||
)
|
||||
--SELECT * FROM seg_json
|
||||
--------------------------------------------------------------------------------
|
||||
-- Stage 4: Merge flags and segment blocks into a single JSON object
|
||||
-- Write final pricing history to pricing.lastpricedetail
|
||||
--------------------------------------------------------------------------------
|
||||
INSERT INTO
|
||||
pricing.lastpricedetail
|
||||
SELECT
|
||||
COALESCE(f.customer, s.customer) AS customer,
|
||||
COALESCE(f.partgroup, s.partgroup) AS partgroup,
|
||||
CONCAT(
|
||||
'{',
|
||||
COALESCE(f.json_block, ''),
|
||||
CASE
|
||||
WHEN f.json_block IS NOT NULL AND s.json_block IS NOT NULL THEN ','
|
||||
ELSE ''
|
||||
END,
|
||||
COALESCE(s.json_block, ''),
|
||||
'}'
|
||||
) AS part_stats
|
||||
FROM flag_json f
|
||||
FULL OUTER JOIN seg_json s
|
||||
ON f.customer = s.customer AND f.partgroup = s.partgroup;
|
||||
|
@ -1,20 +0,0 @@
|
||||
CREATE OR ALTER VIEW pricing.plpr AS
|
||||
SELECT
|
||||
yaplnt plnt,
|
||||
LTRIM(RTRIM(a9)) AS comp,
|
||||
a30 AS descr,
|
||||
SUBSTRING(a249, 242, 2) curr,
|
||||
SUBSTRING(a249, 32, 4) AS gl,
|
||||
SUBSTRING(a249, 190, 4) AS ar,
|
||||
SUBSTRING(a249, 182, 4) AS ap,
|
||||
SUBSTRING(a249, 198, 4) AS fa,
|
||||
SUBSTRING(a249, 238, 4) AS ic
|
||||
FROM
|
||||
CMSInterfaceIN.lgdat.plnt
|
||||
INNER JOIN CMSInterfaceIN.lgdat.code ON
|
||||
yacomp = LTRIM(RTRIM(a9))
|
||||
LEFT OUTER JOIN CMSInterfaceIN.lgdat.name ON
|
||||
'C0000' + LTRIM(RTRIM(a9)) = a7
|
||||
WHERE
|
||||
a2 = 'AA'
|
||||
OR a2 IS NULL;
|
@ -1,12 +1,199 @@
|
||||
DROP TABLE pricing.pricelist_ranged;
|
||||
|
||||
CREATE TABLE pricing.pricelist_ranged (
|
||||
jcplcd varchar(5) ,
|
||||
jcpart varchar(20) ,
|
||||
jcunit varchar(3) ,
|
||||
jcvoll numeric(12,5) ,
|
||||
jcpric numeric(12,5) ,
|
||||
vb_from float ,
|
||||
vb_to float ,
|
||||
price float
|
||||
jcplcd varchar(5) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
jcpart varchar(20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
jcunit varchar(3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
|
||||
jcvoll numeric(12,5) NOT NULL,
|
||||
jcpric numeric(12,5) NOT NULL,
|
||||
vb_from float NULL,
|
||||
vb_to float NULL,
|
||||
price float NOT NULL
|
||||
);
|
||||
|
||||
CREATE NONCLUSTERED INDEX pricelist_ranged_idx ON pricing.pricelist_ranged ( jcpart ASC , jcplcd ASC , vb_from ASC , vb_to ASC );
|
||||
CREATE NONCLUSTERED INDEX pricelist_ranged_idx ON FAnalysis.PRICING.pricelist_ranged ( jcpart ASC , jcplcd ASC , vb_from ASC , vb_to ASC ) ;
|
||||
|
||||
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
-----------------------------------------------------------traverse unit of measure graph-----------------------------------------------------------------------
|
||||
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
-------------setup table to hold target conversions---------------------
|
||||
|
||||
|
||||
SELECT DISTINCT
|
||||
jcpart partn
|
||||
,jcunit fu
|
||||
,'PC' tu
|
||||
,cast(null as numeric) factor
|
||||
INTO
|
||||
#anchor
|
||||
FROM
|
||||
cmsinterfacein.lgdat.iprcc
|
||||
WHERE
|
||||
1=1;
|
||||
|
||||
--SELECT * FROM #anchor
|
||||
|
||||
-------pre-build punit stacked on itself with the columns flipped so you can go either direction per join---------
|
||||
SELECT
|
||||
*
|
||||
INTO
|
||||
#g
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
IHPART IHPART,
|
||||
rtrim(IHUNT1) IHUNT1,
|
||||
rtrim(IHUNT2) IHUNT2,
|
||||
IHCNV1 IHCNV1,
|
||||
IHCNV2 IHCNV2
|
||||
FROM
|
||||
CMSInterfaceIN.LGDAT.PUNIT pu
|
||||
--only deal with parts in the anchor table or the &&global parts
|
||||
INNER JOIN (
|
||||
SELECT DISTINCT partn FROM #anchor
|
||||
) items ON
|
||||
items.partn = pu.ihpart
|
||||
OR pu.ihpart = '&&GLOBAL'
|
||||
UNION
|
||||
SELECT
|
||||
IHPART IHPART,
|
||||
rtrim(IHUNT2) IHUNT1,
|
||||
rtrim(IHUNT1) IHUNT2,
|
||||
IHCNV2 IHCNV1,
|
||||
IHCNV1 IHCNV2
|
||||
FROM
|
||||
CMSInterfaceIN.LGDAT.PUNIT pu
|
||||
--only deal with parts in the anchor table or the &&global parts
|
||||
INNER JOIN (
|
||||
SELECT DISTINCT partn FROM #anchor
|
||||
) items ON
|
||||
items.partn = pu.ihpart
|
||||
OR pu.ihpart = '&&GLOBAL'
|
||||
) x ;
|
||||
|
||||
CREATE INDEX g_idx on #g(ihpart,ihunt1);
|
||||
|
||||
WITH
|
||||
--------do the expansion on all paths until the target uom is matched----------------------------------------------
|
||||
--(complains about types not matching between anchor and recursion, explicitly just casting everything)
|
||||
uom (partn, partx, lvl, mastf, mastt, xf, xt, factor, xfactor, xnum, xden, id, uom_list) AS
|
||||
(
|
||||
SELECT
|
||||
cast(partn as varchar(20)) --partn
|
||||
,cast(partn as varchar(20)) --partx
|
||||
,cast(0 as int) --lvl
|
||||
,fu --mastf
|
||||
,tu --mastt
|
||||
,cast(fu as varchar(3)) --xf
|
||||
,cast(fu as varchar(3)) --xt
|
||||
,CAST(1 AS FLOAT) --factor
|
||||
,CAST(1 AS FLOAT) --xfactor
|
||||
,CAST(1 AS FLOAT) --xnum
|
||||
,CAST(1 AS FLOAT) --xden
|
||||
,format(row_number() over (ORDER BY partn),'000000')
|
||||
,cast(trim(fu) as varchar(max))
|
||||
FROM
|
||||
#anchor
|
||||
UNION ALL
|
||||
SELECT
|
||||
cast(uom.partn as varchar(20)) --partn
|
||||
,cast(ihpart as varchar(20)) --partx
|
||||
,CAST(uom.lvl + 1 AS INT) --lvl
|
||||
,uom.mastf --mastf
|
||||
,uom.mastt --mastt
|
||||
,cast(p.ihunt1 as varchar(3)) --xf
|
||||
,cast(p.ihunt2 as varchar(3)) --xt
|
||||
,CAST(p.ihcnv2/p.ihcnv1 AS FLOAT) --factor
|
||||
,CAST(p.ihcnv2/p.ihcnv1 AS FLOAT) * uom.xfactor --xfactor
|
||||
,p.ihcnv2 * uom.xnum --xnum
|
||||
,p.ihcnv1 * uom.xden --xden
|
||||
,uom.id + '.' + format(row_number() over (PARTITION BY uom.id ORDER BY partn),'00')
|
||||
,uom.uom_list + '.' + trim(p.ihunt2)
|
||||
FROM
|
||||
uom
|
||||
INNER JOIN #g p ON
|
||||
p.ihpart IN (uom.partn,'&&GLOBAL')
|
||||
AND p.ihunt1 = uom.xt
|
||||
WHERE
|
||||
1=1
|
||||
--AND p.ihunt2 not in ('BD','BG','BU','BX','CA','CS','PA','PL','SL','C','K','DOZ','PR')
|
||||
AND p.ihunt1 <> uom.mastt
|
||||
--prevent recursion: newest joined UOM can't be in the history
|
||||
AND charindex(p.ihunt2,uom.uom_list) = 0
|
||||
)
|
||||
--SELECT COUNT(*) FROM UOM
|
||||
--------------uom is going to have multiple rows per requested conversion, need to use row_number to pick the best row------------------------------
|
||||
,sorted AS (
|
||||
SELECT
|
||||
partn, mastf from_uom, xt to_uom, xfactor factor, lvl steps, row_number() OVER (PARTITION BY partn, mastf, mastt ORDER BY lvl ASC, factor ASC) rn
|
||||
FROM
|
||||
uom
|
||||
WHERE
|
||||
xt = mastt
|
||||
)
|
||||
SELECT * INTO #uom FROM sorted WHERE rn = 1;
|
||||
--so far so good
|
||||
|
||||
drop table #anchor;
|
||||
drop table #g;
|
||||
|
||||
TRUNCATE TABLE pricing.pricelist_ranged;
|
||||
|
||||
WITH
|
||||
conv AS (
|
||||
SELECT
|
||||
p.jcplcd,
|
||||
p.jcpart,
|
||||
p.jcunit,
|
||||
p.jcvoll,
|
||||
p.jcpric,
|
||||
u.factor,
|
||||
-- Normalize volume and price to PC
|
||||
p.jcvoll * u.factor AS vol_pc,
|
||||
p.jcpric / u.factor AS price_pc
|
||||
FROM
|
||||
cmsinterfacein.lgdat.iprcc p
|
||||
INNER JOIN #uom u
|
||||
ON u.partn = p.jcpart
|
||||
AND u.from_uom = p.jcunit
|
||||
AND u.to_uom = 'PC'
|
||||
),
|
||||
sorted AS (
|
||||
SELECT
|
||||
c.*,
|
||||
ROW_NUMBER() OVER (PARTITION BY c.jcplcd, c.jcpart ORDER BY vol_pc ASC) AS rn
|
||||
FROM conv c
|
||||
),
|
||||
ranged AS (
|
||||
SELECT
|
||||
curr.jcplcd,
|
||||
curr.jcpart,
|
||||
curr.jcunit,
|
||||
curr.jcvoll,
|
||||
curr.jcpric,
|
||||
curr.vol_pc,
|
||||
curr.price_pc,
|
||||
curr.vol_pc AS vb_from,
|
||||
COALESCE(next.vol_pc, 9999999.0) AS vb_to
|
||||
FROM
|
||||
sorted curr
|
||||
LEFT JOIN sorted next
|
||||
ON curr.jcplcd = next.jcplcd
|
||||
AND curr.jcpart = next.jcpart
|
||||
AND curr.rn + 1 = next.rn
|
||||
)
|
||||
INSERT INTO
|
||||
pricing.pricelist_ranged
|
||||
SELECT
|
||||
RTRIM(jcplcd) jcplcd,
|
||||
RTRIM(jcpart) jcpart,
|
||||
jcunit,
|
||||
jcvoll,
|
||||
jcpric,
|
||||
vb_from,
|
||||
vb_to,
|
||||
price_pc AS price
|
||||
FROM
|
||||
ranged;
|
||||
|
||||
--CREATE INDEX pricelist_ranged_idx ON pricing.pricelist_ranged(jcpart, jcplcd, vb_from, vb_to);
|
||||
|
@ -1,11 +1,101 @@
|
||||
CREATE TABLE pricelist_ranged (
|
||||
jcplcd text NULL,
|
||||
jcpart text NULL,
|
||||
jcunit text NULL,
|
||||
jcvoll numeric(12, 5) NULL,
|
||||
jcpric numeric(12, 5) NULL,
|
||||
vb_from numeric NULL,
|
||||
vb_to numeric NULL,
|
||||
price numeric NULL
|
||||
);
|
||||
CREATE INDEX pricelist_ranged_idx ON pricequote.pricelist_ranged USING btree (jcpart, jcplcd, vb_from, vb_to);
|
||||
DROP TABLE IF EXISTS uomc;
|
||||
|
||||
CREATE TEMP TABLE uomc AS (
|
||||
WITH
|
||||
uom AS (
|
||||
SELECT
|
||||
uom.p part
|
||||
,uom.f fu
|
||||
,uom.t tu
|
||||
,uom.nm/uom.dm conv
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
jsonb_agg(row_to_json(d)::jsonb) jdoc
|
||||
FROM
|
||||
(
|
||||
select distinct
|
||||
jcpart partn
|
||||
, jcunit fu
|
||||
, 'PC' tu
|
||||
from
|
||||
lgdat.iprcc
|
||||
WHERE
|
||||
jcpart <> ''
|
||||
) d
|
||||
) c
|
||||
JOIN LATERAL rlarp.uom_array(c.jdoc) uom ON TRUE
|
||||
)
|
||||
SELECT * FROM uom
|
||||
) WITH DATA;
|
||||
|
||||
CREATE INDEX uom_idx ON uomc (part, fu, tu);
|
||||
|
||||
|
||||
-- Clear the output table
|
||||
TRUNCATE TABLE pricequote.pricelist_ranged;
|
||||
|
||||
--DROP TABLE pricequote.pricelist_ranged;
|
||||
|
||||
-- Compute normalized volume/price and ranges
|
||||
--CREATE TABLE pricequote.pricelist_ranged AS (
|
||||
WITH
|
||||
conv AS (
|
||||
SELECT
|
||||
p.jcplcd,
|
||||
p.jcpart,
|
||||
p.jcunit,
|
||||
p.jcvoll,
|
||||
p.jcpric,
|
||||
u.conv,
|
||||
(p.jcvoll * u.conv) AS vol_pc,
|
||||
(p.jcpric / NULLIF(u.conv, 0)) AS price_pc
|
||||
FROM
|
||||
lgdat.iprcc p
|
||||
INNER JOIN uomc u
|
||||
ON u.part = p.jcpart
|
||||
AND u.fu = p.jcunit
|
||||
AND u.tu = 'PC'
|
||||
),
|
||||
--SELECT * FROM conv LIMIT 1000
|
||||
sorted AS (
|
||||
SELECT
|
||||
*,
|
||||
ROW_NUMBER() OVER (PARTITION BY jcplcd, jcpart ORDER BY vol_pc ASC) AS rn
|
||||
FROM conv
|
||||
),
|
||||
ranged AS (
|
||||
SELECT
|
||||
curr.jcplcd,
|
||||
curr.jcpart,
|
||||
curr.jcunit,
|
||||
curr.jcvoll,
|
||||
curr.jcpric,
|
||||
curr.vol_pc,
|
||||
curr.price_pc price,
|
||||
curr.vol_pc AS vb_from,
|
||||
COALESCE(next.vol_pc, 9999999.0) AS vb_to
|
||||
FROM
|
||||
sorted curr
|
||||
LEFT JOIN sorted next
|
||||
ON curr.jcplcd = next.jcplcd
|
||||
AND curr.jcpart = next.jcpart
|
||||
AND curr.rn + 1 = next.rn
|
||||
)
|
||||
--SELECT * FROM ranged
|
||||
INSERT INTO pricequote.pricelist_ranged (
|
||||
jcplcd, jcpart, jcunit, jcvoll, jcpric, vb_from, vb_to, price
|
||||
)
|
||||
SELECT
|
||||
jcplcd,
|
||||
jcpart,
|
||||
jcunit,
|
||||
jcvoll,
|
||||
jcpric,
|
||||
vb_from,
|
||||
vb_to,
|
||||
price
|
||||
FROM ranged;
|
||||
|
||||
|
||||
CREATE INDEX pricelist_ranged_idx ON pricequote.pricelist_ranged ( jcpart ASC , jcplcd ASC , vb_from ASC , vb_to ASC ) ;
|
@ -1 +0,0 @@
|
||||
SELECT * INTO pricing.pricing.qrh FROM fanalysis.RLARP.QRH q
|
27
tables/rebuild_targets.pg.sql
Normal file
27
tables/rebuild_targets.pg.sql
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
DELETE FROM pricequote.target_prices_base;
|
||||
|
||||
WITH
|
||||
expand AS (
|
||||
SELECT
|
||||
c.compset,
|
||||
c.stlc,
|
||||
c.floor,
|
||||
b.ds,
|
||||
b.chan,
|
||||
b.tier,
|
||||
b.vol,
|
||||
b.val,
|
||||
b.price,
|
||||
b.math math
|
||||
FROM
|
||||
pricequote.core_target c
|
||||
LEFT JOIN LATERAL pricequote.build_pricing_path_base (options||jsonb_build_object('entity','Anchor','attr',c.stlc,'val',c.floor,'func','Price')) b ON b.lastflag
|
||||
)
|
||||
-- select count(*) from expand
|
||||
INSERT INTO
|
||||
pricequote.target_prices_base
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
expand;
|
@ -1,18 +0,0 @@
|
||||
CREATE OR ALTER VIEW pricing.repc AS
|
||||
WITH
|
||||
code AS (
|
||||
SELECT
|
||||
ltrim(rtrim(c.a9)) rcode
|
||||
,(ltrim(rtrim(c.a9)) + ' - ') + c.a30 repp
|
||||
FROM
|
||||
CMSInterfaceIN.lgdat.code c
|
||||
WHERE c.a2 = 'MM'
|
||||
)
|
||||
SELECT
|
||||
COALESCE(c.rcode,q.qr) rcode
|
||||
,COALESCE(c.repp,q.qr) repp
|
||||
,COALESCE(q.dir,'Other') director
|
||||
FROM
|
||||
code c
|
||||
FULL OUTER JOIN pricing.qrh q ON
|
||||
q.qr = c.rcode
|
@ -1 +0,0 @@
|
||||
SELECT * INTO pricing.sach FROM fanalysis.lgdat.sach;
|
@ -16,4 +16,26 @@ ALTER TABLE pricing.target_prices
|
||||
ADD CONSTRAINT uq_target_prices_unique_combo
|
||||
UNIQUE (stlc, ds, chan, tier, vol, lower_bound);
|
||||
|
||||
DELETE FROM pricing.target_prices;
|
||||
|
||||
INSERT INTO
|
||||
pricing.target_prices
|
||||
SELECT
|
||||
stlc,
|
||||
ds,
|
||||
chan,
|
||||
tier,
|
||||
vol,
|
||||
-- Extract lower bound: text between '[' and ','
|
||||
TRY_CAST(SUBSTRING(vol, 2, CHARINDEX(',', vol) - 2) AS INT) AS lower_bound,
|
||||
-- Extract upper bound: text between ',' and ')'
|
||||
CASE
|
||||
WHEN RIGHT(vol, 2) = ',)' THEN NULL
|
||||
ELSE TRY_CAST(SUBSTRING(vol, CHARINDEX(',', vol) + 1, LEN(vol) - CHARINDEX(',', vol) - 1) AS INT)
|
||||
END AS upper_bound,
|
||||
price,
|
||||
math
|
||||
FROM
|
||||
usmidsap02.ubm.pricequote.target_prices_view;
|
||||
|
||||
--SELECT COUNT(*) FROM pricing.target_prices
|
||||
|
Loading…
Reference in New Issue
Block a user