Row number by 3 distincts fields in SQL Server - sql-server

I have this table:
| RecordLocator | DepartureStation | ArrivalStation | JourneyNumber | SegmentNumber | LegNumber | FlightNumber |
|---------------|------------------|----------------|---------------|---------------|-----------|--------------|
| DADABC | MAO | GRU | 2 | 1 | 1 | 1421 |
| CEDLDA | MAO | STM | 1 | 2 | 1 | 1643 |
| CEDLDA | GRU | MAO | 1 | 1 | 1 | 1640 |
| DADABC | GRU | FLN | 1 | 1 | 1 | 1848 |
| CEDLDA | BEL | SLZ | 1 | 2 | 3 | 1643 |
| DADABC | GIG | FOR | 1 | 2 | 3 | 1154 |
| CEDLDA | SLZ | FOR | 1 | 2 | 4 | 1680 |
| CEDLDA | FOR | REC | 1 | 2 | 5 | 1680 |
| DADABC | FOR | MAO | 1 | 2 | 4 | 1982 |
| CEDLDA | REC | SSA | 1 | 2 | 6 | 1680 |
| CEDLDA | STM | BEL | 1 | 2 | 2 | 1643 |
| DADABC | POA | GIG | 1 | 2 | 2 | 1201 |
| CEDLDA | SSA | GRU | 1 | 3 | 1 | 1817 |
| DADABC | FLN | POA | 1 | 2 | 1 | 1201 |
I want add a new column row number based on JourneyNumber, SegmentNumber and LegNumber, order by RecordLocator, for obtain this result:
| RecordLocator | DepartureStation | ArrivalStation | JourneyNumber | SegmentNumber | LegNumber | FlightNumber | rowNum |
|---------------|------------------|----------------|---------------|---------------|-----------|--------------|--------|
| CEDLDA | GRU | MAO | 1 | 1 | 1 | 1640 | 1 |
| CEDLDA | MAO | STM | 1 | 2 | 1 | 1643 | 2 |
| CEDLDA | STM | BEL | 1 | 2 | 2 | 1643 | 3 |
| CEDLDA | BEL | SLZ | 1 | 2 | 3 | 1643 | 4 |
| CEDLDA | SLZ | FOR | 1 | 2 | 4 | 1680 | 5 |
| CEDLDA | FOR | REC | 1 | 2 | 5 | 1680 | 6 |
| CEDLDA | REC | SSA | 1 | 2 | 6 | 1680 | 7 |
| CEDLDA | SSA | GRU | 1 | 3 | 1 | 1817 | 8 |
| DADABC | GRU | FLN | 1 | 1 | 1 | 1848 | 1 |
| DADABC | FLN | POA | 1 | 2 | 1 | 1201 | 2 |
| DADABC | POA | GIG | 1 | 2 | 2 | 1201 | 3 |
| DADABC | GIG | FOR | 1 | 2 | 3 | 1154 | 4 |
| DADABC | FOR | MAO | 1 | 2 | 4 | 1982 | 5 |
| DADABC | MAO | GRU | 2 | 1 | 1 | 1421 | 6 |
I tried this query:
SELECT
RecordLocator,
DepartureStation, ArrivalStation,
JourneyNumber, SegmentNumber,
LegNumber, FlightNumber,
(SELECT ((P.JourneyNumber + P.SegmentNumber + P.LegNumber))
FROM PAX P2
WHERE P2.RecordLocator = P.RecordLocator
AND P2.DepartureStation = P.DepartureStation
AND P2.ArrivalStation = P.ArrivalStation
AND P2.JourneyNumber = P.JourneyNumber
AND P2.SegmentNumber = P.SegmentNumber
AND P2.LegNumber = P.LegNumber
AND P2.FlightNumber = P.FlightNumber) AS rowNum
FROM
PAX P
I'm trying sum the columns JourneyNumber, SegmentNumber and LegNumber but does not work, i belive best way to do, is based on Recordlocator define a "weight" for the columns JourneyNumber > SegmentNumber > LegNumber, but i don't know how implement it.
In C# I know how to do it, using align for:
// First `for` - Journey
for(int i = 0; i < Journey.Count(); i++)
{
// Second `for` - Segment
for(int j = 0; j < Segment.Count(); j++)
{
// Third `for` - Leg
for(int k = 0; k < Leg.Count(); k++)
{
result = i + j + k;
}
}
}

Basically, breaking down your question into its parts, you want to re-start numbering for each RecordLocator, then you order it by the 3 fields you wanted in ascending order.
Overall, that's the idea of the ROW_NUMBER() which allows for ordering your records with a partition set for RecordLocator to re-start the numbering as needed. So, something like this should do it:
ROW_NUMBER() OVER(PARTITION BY RecordLocator ORDER BY JourneyNumber, SegmentNumber, LegNumber)
And your final SQL, therefore, becoming:
SELECT RecordLocator
, DepartureStation
, ArrivalStation
, JourneyNumber
, SegmentNumber
, LegNumber
, FlightNumber
, ROW_NUMBER() OVER(PARTITION BY RecordLocator ORDER BY JourneyNumber, SegmentNumber, LegNumber) AS rowNum
FROM PAX P
Hope this does the trick!

Related

SQL I want to figure out how to get sales 10 days for each product and within each group

I have a SQL Server table T1 that has orders by product_id, brand, and size for each day.
T1:
+------------+-------+------+----------+--------+
| product_id | Brand | Size | Date | Orders |
+------------+-------+------+----------+--------+
| 1 | 1 | 11 | 10/18/18 | 1 |
| 1 | 1 | 6 | 10/18/18 | 2 |
| 1 | 1 | 10 | 10/18/18 | 1 |
| 1 | 1 | 7 | 10/18/18 | 3 |
| 1 | 1 | 8.5 | 10/18/18 | 5 |
| 1 | 1 | 9.5 | 10/18/18 | 2 |
| 2 | 1 | 8 | 10/19/18 | 3 |
| 2 | 1 | 7 | 10/19/18 | 6 |
| 2 | 1 | 9 | 10/19/18 | 2 |
| 3 | 2 | 5 | 10/19/18 | 23 |
| 3 | 2 | 6 | 10/19/18 | 6 |
| 3 | 2 | 10 | 10/19/18 | 7 |
+------------+-------+------+----------+--------+
I also have a table, T2, that has the launch date for each product_id. A product_id may have more than one launch dates, signifying it is "restocked".
T2:
+------------+-------------+
| product_id | launch_date |
+------------+-------------+
| 1 | 8/18/18 |
| 1 | 10/18/18 |
| 2 | 10/18/18 |
| 3 | 4/18/18 |
+------------+-------------+
My goal is to create a table that is just the first 10 days of orders in each launch date (for each product_id, brand, and size). So if launch date for product 1 is 8/18/18 and 10/18/18, then I want the daily orders from 8/18/18 to 8/28/18, and from 10/18/18 to 10/28/18.
How would I go about creating this table?
Example output:
+------------+-------+------+----------+--------+
| product_id | Brand | Size | Date | Orders |
+------------+-------+------+----------+--------+
| 1 | 1 | 11 | 10/18/18 | 1 |
| 1 | 1 | 6 | 10/18/18 | 2 |
| 1 | 1 | 10 | 10/18/18 | 1 |
| 1 | 1 | 7 | 10/18/18 | 3 |
| 1 | 1 | 8.5 | 10/18/18 | 5 |
| 1 | 1 | 9.5 | 10/18/18 | 2 |
| … | | | | |
| 1 | 1 | 11 | 10/22/18 | 4 |
| 1 | 1 | 6 | 10/22/18 | 6 |
| 1 | 1 | 10 | 10/22/18 | 2 |
| 1 | 1 | 7 | 10/22/18 | 2 |
| 1 | 1 | 8.5 | 10/22/18 | 2 |
| 1 | 1 | 9.5 | 10/22/18 | 5 |
| … | | | | |
| 1 | 1 | 11 | 10/28/18 | 7 |
| 1 | 1 | 6 | 10/28/18 | 4 |
| 1 | 1 | 10 | 10/28/18 | 2 |
| 1 | 1 | 7 | 10/28/18 | 2 |
| 1 | 1 | 8.5 | 10/28/18 | 8 |
| 1 | 1 | 9.5 | 10/28/18 | 7 |
| … | | | | |
| 2 | 1 | 8 | 10/19/18 | 3 |
| 2 | 1 | 7 | 10/19/18 | 6 |
| 2 | 1 | 9 | 10/19/18 | 2 |
| 3 | 2 | 5 | 10/19/18 | 23 |
| 3 | 2 | 6 | 10/19/18 | 6 |
| 3 | 2 | 10 | 10/19/18 | 7 |
+------------+-------+------+----------+--------+
Thank you!
EDIT: including what I have tried so far:
My thought process is to try to create to join the launch_date and then create a column that is the number of days between the launch date and the Date of order. Then I can just filter for WHERE that column is less than or equal to 10.
This is the query I am using:
with temp as (
select
t1.product_id, t1.brand, t1.size, t1.date, t1.orders, t2.launch_date
from t1
left join t2 on t1.product_id = t2.product_id and t1.order_date = t2.order_date
)
select product_id,
brand,
size,
size,
date,
orders,
launch_date
from temp
;
In order for my reasoning to work, I would need to forward-fill the launch_date wherever it is null. I am not sure how to accomplish this. Here is the output I have so far:
+------------+-------+------+----------+--------+-------------+
| product_id | Brand | Size | Date | Orders | launch_date |
+------------+-------+------+----------+--------+-------------+
| 1 | 1 | 11 | 10/18/18 | 1 | 10/18/18 |
| 1 | 1 | 6 | 10/18/18 | 2 | 10/18/18 |
| 1 | 1 | 10 | 10/18/18 | 1 | 10/18/18 |
| 1 | 1 | 7 | 10/18/18 | 3 | 10/18/18 |
| 1 | 1 | 8.5 | 10/18/18 | 5 | 10/18/18 |
| 1 | 1 | 9.5 | 10/18/18 | 2 | 10/18/18 |
| … | | | | | |
| 1 | 1 | 11 | 10/22/18 | 4 | NULL |
| 1 | 1 | 6 | 10/22/18 | 6 | NULL |
| 1 | 1 | 10 | 10/22/18 | 2 | NULL |
| 1 | 1 | 7 | 10/22/18 | 2 | NULL |
| 1 | 1 | 8.5 | 10/22/18 | 2 | NULL |
| 1 | 1 | 9.5 | 10/22/18 | 5 | NULL |
| … | | | | | |
| 1 | 1 | 11 | 10/28/18 | 7 | NULL |
| 1 | 1 | 6 | 10/28/18 | 4 | NULL |
| 1 | 1 | 10 | 10/28/18 | 2 | NULL |
| 1 | 1 | 7 | 10/28/18 | 2 | NULL |
| 1 | 1 | 8.5 | 10/28/18 | 8 | NULL |
| 1 | 1 | 9.5 | 10/28/18 | 7 | NULL |
| … | | | | | |
| 2 | 1 | 8 | 10/19/18 | 3 | 10/18/18 |
| 2 | 1 | 7 | 10/19/18 | 6 | 10/18/18 |
| 2 | 1 | 9 | 10/19/18 | 2 | 10/18/18 |
| 3 | 2 | 5 | 10/19/18 | 23 | 10/18/18 |
| 3 | 2 | 6 | 10/19/18 | 6 | 10/18/18 |
| 3 | 2 | 10 | 10/19/18 | 7 | 10/18/18 |
+------------+-------+------+----------+--------+-------------+
If I can forward-fill the launch_date wherever it is NULL to be the most recent launch_date of that product_id, then I would be able to create a column to subtract the dates.

SQL query to aggregate result from child table

I need to join 4 table and display records in my application
route1
-------------------------
| ID | MODE | SCH DATE |
| 1 | T | 1/12019 |
| 2 | T | 2/12019 |
| 3 | T | 2/12019 |
--------------------------
Stop2
----------------------------
| ID | routeID | LocationID |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 4 |
| 5 | 2 | 5 |
| 6 | 3 | 6 |
-----------------------------
StopOrder2
----------------------------
| ID | StopID | Wight |
| 1 | 1 | 100 |
| 2 | 1 | 2 |
| 3 | 2 | 3 |
| 4 | 2 | 1 |
| 5 | 3 | 2 |
| 6 | 3 | 3 |
| 7 | 4 | 2 |
| 8 | 4 | 3 |
| 9 | 5 | 2 |
| 10 | 5 | 3 |
| 11 | 6 | 2 |
| 12 | 6 | 3 |
-----------------------------
Location
| LocationID | Name, City, Zip
| 1 | name1,city1 1111
| 2 | name2,city2 2222
| 3 | name3,city3 333
-----------------------------
I want final result with each route have how many records and how many orders and sum of all order wight
-----------------------------------------
| RouteID | MODE | SCH DATE |No Of Stop |LastLocatioID|OrderCount|
| 1 | T | 1/12019 | 3 | 3 | 6 |
| 2 | T | 2/12019 | 2 | 5 | 4 |
| 3 | T | 2/12019 | 1 | 6 | 2 |
How can I write the SQL query I need?
All you need is a simple group by:
SELECT
r.ID AS RouteID,
r.MODE,
r.[SCH DATE],
COUNT(s.ID) AS [No Of Stop],
MAX(s.LocationID) AS [LastLocationID],
COUNT(o.ID) AS OrderCount
FROM
#route1 r
INNER JOIN #Stop2 s
ON r.ID = s.routeID
INNER JOIN #StopOrder2 o
ON s.ID = o.StopID
GROUP BY
r.ID,
r.MODE,
r.[SCH DATE]
Output:

How to hide duplicate rows and display 4 count texts in 4 columns

I want to hide duplicate rows based on 2 columns (row,type)
In the status column I have 4 types of text
Enable,Disable,Run,End
Also 4 extra columns for these 4 texts
The number of each text based on that 2 columns is displayed in the corresponding column
I want to convert from :
|--------------------------------|
| id | row |value | type |status |
|--------------------------------|
| 1 | a | a | a |Enable |
| 2 | a | a | a |Disable|
| 3 | a | a | a |Run |
| 4 | a | a | a |End |
| 5 | a | a | a |End |
| |
| 6 | a | a | b |Enable |
| 7 | a | a | b |Run |
| |
| 8 | b | a | b |Enable |
| 9 | b | a | b |Disable|
| |
| 10 | b | a | c |Run |
| 11 | b | a | c |End |
| 12 | b | a | c |End |
| |
| 13 | c | a | a |Enable |
| 14 | c | a | a |Run |
|--------------------------------|
to :
|---------------------------------------------------------------|
| id | row |value | type |status |number |Enable|Disable|Run|End|
|---------------------------------------------------------------|
| 1 | a | a | a |Enable | 5 | 1 | 1 | 1 | 2 |
| 2 | a | a | b |Enable | 2 | 1 | 0 | 1 | 0 |
| 3 | b | a | b |Enable | 2 | 1 | 1 | 0 | 0 |
| 4 | b | a | c |Run | 3 | 0 | 0 | 1 | 2 |
| 5 | c | a | a |Enable | 2 | 1 | 0 | 1 | 0 |
|---------------------------------------------------------------|
my query :
SELECT
ROW_NUMBER() OVER(order by min(id)) AS 'id'
, row
, MIN(value) AS 'value'
, type
, MIN(status) AS 'status'
, COUNT(*) AS'number'
, (SELECT COUNT(1) FROM Work WHERE status LIKE 'Enable' ) AS 'Enable'
, (SELECT COUNT(1) FROM Work WHERE status LIKE 'Disable' ) AS 'Disable'
, (SELECT COUNT(1) FROM Work WHERE status LIKE'Run') AS 'Run'
, (SELECT COUNT(1) FROM Work WHERE status LIKE 'End') AS 'End'
FROM Work AS w
WHERE type ='a'
GROUP BY row,type
ORDER BY MIN(id)
But with this query the output is :
|---------------------------------------------------------------|
| id | row |value | type |status |number |Enable|Disable|Run|End|
|---------------------------------------------------------------|
| 1 | a | a | a |Enable | 5 | 1 | 1 | 1 | 2 |
| 2 | a | a | b |Enable | 2 | 1 | 1 | 1 | 2 |
| 3 | b | a | b |Enable | 2 | 1 | 1 | 1 | 2 |
| 4 | b | a | c |Run | 3 | 1 | 1 | 1 | 2 |
| 5 | c | a | a |Enable | 2 | 1 | 1 | 1 | 2 |
|---------------------------------------------------------------|
There is missing where part in every select count(*)... .
...
,(select count(*) from Work w2 where status like 'Enable' and w.row = w2.row and w.type = w2.type ) as 'Enable'
...

Sum, Group by and Null

I'm dipping my toes into SQL. I have the following table
+------+----+------+------+-------+
| Type | ID | QTY | Rate | Name |
+------+----+------+------+-------+
| B | 1 | 1000 | 21 | Jack |
| B | 2 | 2000 | 12 | Kevin |
| B | 1 | 3000 | 24 | Jack |
| B | 1 | 1000 | 23 | Jack |
| B | 3 | 200 | 13 | Mary |
| B | 2 | 3000 | 12 | Kevin |
| B | 4 | 4000 | 44 | Chris |
| B | 4 | 5000 | 43 | Chris |
| B | 3 | 1000 | 26 | Mary |
+------+----+------+------+-------+
I don't know how I would leverage Sum and Group by to achieve the following result.
+------+----+------+------+-------+------------+
| Type | ID | QTY | Rate | Name | Sum of QTY |
+------+----+------+------+-------+------------+
| B | 1 | 1000 | 21 | Jack | 5000 |
| B | 1 | 3000 | 24 | Jack | Null |
| B | 1 | 1000 | 23 | Jack | Null |
| B | 2 | 3000 | 12 | Kevin | 5000 |
| B | 2 | 3000 | 12 | Kevin | Null |
| B | 3 | 200 | 13 | Mary | 1200 |
| B | 3 | 1000 | 26 | Mary | Null |
| B | 4 | 4000 | 44 | Chris | 9000 |
| B | 4 | 5000 | 43 | Chris | Null |
+------+----+------+------+-------+------------+
Any help is appreciated!
You can use window function :
select t.*,
(case when row_number() over (partition by type, id order by name) = 1
then sum(qty) over (partition by type, id order by name)
end) as Sum_of_QTY
from table t;

Need to update "orderby" column

I have a table test
+----+--+------+--+--+----------+--+--------------+
| ID | | Name | | | orderby | | processgroup |
+----+--+------+--+--+----------+--+--------------+
| 1 | | ABC | | | 10 | | 1 |
| 10 | | DEF | | | 12 | | 1 |
| 15 | | LMN | | | 1 | | 1 |
| 44 | | JKL | | | 4 | | 1 |
| 42 | | XYZ | | | 3 | | 2 |
+----+--+------+--+--+----------+--+--------------+
I want to update the orderby column in the sequence, I am expecting output like
+----+--+------+--+--+----------+--+--------------+
| ID | | Name | | | orderby | | processgroup |
+----+--+------+--+--+----------+--+--------------+
| 1 | | ABC | | | 1 | | 1 |
| 10 | | DEF | | | 2 | | 1 |
| 15 | | LMN | | | 3 | | 1 |
| 44 | | JKL | | | 4 | | 1 |
| 42 | | XYZ | | | 5 | | 1 |
+----+--+------+--+--+----------+--+--------------+
Logic behind this is when we have procesgroup as 1, orderby column should update as 1,2,3,4 and when procesgroup is 2 then update orderby as 5.
This might help you
;WITH CTE AS (
SELECT ROW_NUMBER() OVER (ORDER BY processgroup, ID ) AS SNO, ID FROM TABLE1
)
UPDATE TABLE1 SET TABLE1.orderby= CTE.SNO FROM CTE WHERE TABLE1.ID = CTE.ID

Resources