Group Blank Rows? - sql

I want to turn this:
Query:
select A.DispatchNote, B.MStockCode, B.NComment
from MdnMaster A
left join MdnDetail B on A.DispatchNote = B.DispatchNote
A.DispatchNote
B.MStockCode
B.NComment
258579/0001
RFK2-8520-150-25
258579/0001
FREIGHT
258579/0001
1 Parcel UPS Ground 2/28/2020
258579/0001
Trk#: 1Z8R9V900342021397 -- 0.9 lb
258585/0001
CAW2-1832-25L
258585/0001
FREIGHT
258585/0001
6 Parcels UPS Ground 2/28/2020
258585/0001
Trk#: 1Z8R9V900342126962 -- 15 lb
258585/0001
Trk#: 1Z8R9V900342515176 -- 15 lb
258585/0001
Trk#: 1Z8R9V900340703781 -- 15 lb
258585/0001
Trk#: 1Z8R9V900340988792 -- 15 lb
258585/0001
Trk#: 1Z8R9V900340706204 -- 15 lb
258585/0001
Trk#: 1Z8R9V900342832014 -- 15 lb
into this:
Query:
select A.DispatchNote, B.MStockCode, B.NComment
from MdnMaster A
left join MdnDetail B on A.DispatchNote = B.DispatchNote
where A.Customer = 'LAWSON' -- Not visible here, but the whole query only pulls LAWSON orders
and B.MLineShipDate >= FORMAT(DATEADD(DAY,-4,getdate()),'yyyy-MM-dd 00:00:00.000') -- This pulls only orders from yesterday's date
A.DispatchNote
B.MStockCode
B.NComment
258579/0001
RFK2-8520-150-25
Trk#: 1Z8R9V900342021397 -- 0.9 lb
258585/0001
CAW2-1832-25L
Trk#: 1Z8R9V900342126962 -- 15 lb
But I'm not sure how. When I run my query I get nothing, and I think it's because I'm supposed to do something with a group by but I'm not sure.
Basically I want to clear the empty rows in MStockCode (or condense the rows I guess) and only pull the first visible tracking number that shows up for each dispatchnote when I run the query unsorted).

For the grouping, you can start doing this. it will get less records:
select
A.DispatchNote,
B.MStockCode,
B.NComment
from MdnMaster A
left join MdnDetail B on A.DispatchNote = B.DispatchNote
and (B.NComment LIKE 'Trk%' OR B.MStockCode is not null)
Combining them on 1 line:
select
A.DispatchNote,
MAX(B.MStockCode) as StockCode,
MAX(B.NComment) as Comment
from MdnMaster A
left join MdnDetail B on A.DispatchNote = B.DispatchNote
and (B.NComment LIKE 'Trk%' OR B.MStockCode is not null)
group by A.DispatchNote

I created a small script in T-SQL so I could run and debug with your data. I added one sample record to verify the behavior when there is no tracking information.
DECLARE #MdnMaster TABLE (DispatchNote VARCHAR(50) NOT NULL);
DECLARE #MdnDetail TABLE (DispatchNote VARCHAR(50) NOT NULL, MStockCode VARCHAR(50) NULL, NComment VARCHAR(50) NULL);
INSERT INTo #MdnMaster(DispatchNote) VALUES ('258579/0001'),('258579/0001'),('258579/0001'),('258579/0001'),
('258585/0001'),('258585/0001'),('258585/0001'),('258585/0001'),('258585/0001'),('258585/0001'),
('258585/0001'),('258585/0001'),('258585/0001'),('999999/TEST');
INSERT INTO #MdnDetail(DispatchNote, MStockCode, NComment) VALUES
('258579/0001','RFK2-8520-150-25',NULL)
,('258579/0001',NULL,'FREIGHT')
,('258579/0001',NULL,'1 Parcel UPS Ground 2/28/2020')
,('258579/0001',NULL,'Trk#: 1Z8R9V900342021397 -- 0.9 lb')
,('258585/0001','CAW2-1832-25L',NULL)
,('258585/0001',NULL,'FREIGHT')
,('258585/0001',NULL,'6 Parcels UPS Ground 2/28/2020')
,('258585/0001',NULL,'Trk#: 1Z8R9V900342126962 -- 15 lb')
,('258585/0001',NULL,'Trk#: 1Z8R9V900342515176 -- 15 lb')
,('258585/0001',NULL,'Trk#: 1Z8R9V900340703781 -- 15 lb')
,('258585/0001',NULL,'Trk#: 1Z8R9V900340988792 -- 15 lb')
,('258585/0001',NULL,'Trk#: 1Z8R9V900340706204 -- 15 lb')
,('258585/0001',NULL,'Trk#: 1Z8R9V900342832014 -- 15 lb')
,('999999/TEST','TEST-WITHOUT-TRACKING','No tracking');
SELECT
m.DispatchNote,
MAX(d.MStockCode) as StockCode,
MAX(case when d.NComment like 'Trk%' then d.NComment end) as NComment
FROM #MdnMaster AS m
LEFT OUTER JOIN #MdnDetail AS d on m.DispatchNote = d.DispatchNote
AND (d.NComment LIKE 'Trk%' OR d.MStockCode is not null)
GROUP BY m.DispatchNote
This is the output:
DispatchNote
StockCode
NComment
258579/0001
RFK2-8520-150-25
Trk#: 1Z8R9V900342021397 -- 0.9 lb
258585/0001
CAW2-1832-25L
Trk#: 1Z8R9V900342832014 -- 15 lb
999999/TEST
TEST-WITHOUT-TRACKING
NULL
There are other approaches, but this should work in most RDBMS. For the tables you have, it is simply:
SELECT
m.DispatchNote,
MAX(d.MStockCode) as StockCode,
MAX(case when d.NComment like 'Trk%' then d.NComment end) as NComment
FROM MdnMaster AS m
LEFT OUTER JOIN MdnDetail AS d on m.DispatchNote = d.DispatchNote
AND (d.NComment LIKE 'Trk%' OR d.MStockCode is not null)
GROUP BY m.DispatchNote

Related

SQL query for most recent date

I'm trying to query to only pull the most recent sale date but keep the unique value of "strap". This is the query result I have.
nh_cd strap dor_cd acreage sqft sale date reception_num price asd_val rea_cd
178.00 R0000001 AG 4.7160 205443 2019-07-11 00:00:00.000 3723615 890000 200 05
178.00 R0000001 AG 4.7160 205443 2020-05-29 00:00:00.000 3787823 880000 200 40
205.00 R0022222 AGRES 5.8030 252771 2019-06-10 00:00:00.000 3718473 647500 520200 40
This is what I've built so far, but it doesn't give me my desired result of a recent date.
SELECT distinct
parcel.nh_cd
,sales.strap
,parcel.dor_cd
,detail.acreage
,detail.sqft
,max(sales.dos)
,sales.reception_num
,sales.price
,parcel.asd_val
,sales.rea_cd
,sales.qu_flg
,sales.valid_cd
,sales.vi
,site.str_num
,site.str_pfx
,site.str
,site.str_sfx
,site.city
,parcel.status_cd
,strap_idx.folio
FROM detail INNER JOIN parcel ON parcel.strap = detail.strap
INNER JOIN sales ON parcel.strap = sales.strap
INNER JOIN site ON parcel.strap = site.strap
INNER JOIN strap_idx ON parcel.strap = strap_idx.strap
INNER JOIN lnd_a ON parcel.strap = lnd_a.strap
WHERE lnd_a.st_use_cd IN ('4117','4127','4137','4147','4167','4177','4180')
AND parcel.dor_cd LIKE 'AG%'
AND parcel.status_cd = 'A'
AND (sales.price > '0')
AND (site.ln_num = '1')
AND (sales.dos>='07/01/2018')
AND (sales.dos<='08/24/2020')
GROUP by parcel.nh_cd
,sales.strap
,parcel.dor_cd
,detail.acreage
,detail.sqft
,sales.dos
,sales.reception_num
,sales.price
,parcel.asd_val
,sales.rea_cd
,sales.qu_flg
,sales.valid_cd
,sales.vi
,site.str_num
,site.str_pfx
,site.str
,site.str_sfx
,site.city
,parcel.status_cd
,strap_idx.folio
This is the result I want
nh_cd strap dor_cd acreage sqft sale date reception_num price asd_val rea_cd
178.00 R0000001 AG 4.7160 205443 2020-05-29 00:00:00.000 3787823 880000 200 40
205.00 R0022222 AGRES 5.8030 252771 2019-06-10 00:00:00.000 3718473 647500 520200 40
How would I go about doing this?
You can ROW_NUMBER() it
SELECT *
FROM (
SELECT distinct parcel.nh_cd
,sales.strap
,parcel.dor_cd
,detail.acreage
,detail.sqft
,sales.dos
,sales.reception_num
,sales.price
,parcel.asd_val
,sales.rea_cd
,sales.qu_flg
,sales.valid_cd
,sales.vi
,site.str_num
,site.str_pfx
,site.str
,site.str_sfx
,site.city
,parcel.status_cd
,strap_idx.folio
, ROW_NUMBER() OVER(PARTITION BY parcel.nh_cd, sales.strap ORDER BY sales.dos DESC) AS rn
FROM detail INNER JOIN parcel ON parcel.strap = detail.strap
INNER JOIN sales ON parcel.strap = sales.strap
INNER JOIN site ON parcel.strap = site.strap
INNER JOIN strap_idx ON parcel.strap = strap_idx.strap
INNER JOIN lnd_a ON parcel.strap = lnd_a.strap
WHERE lnd_a.st_use_cd IN ('4117','4127','4137','4147','4167','4177','4180')
AND parcel.dor_cd LIKE 'AG%'
AND parcel.status_cd = 'A'
AND (sales.price > '0')
AND (site.ln_num = '1')
AND (sales.dos>='07/01/2018')
AND (sales.dos<='08/24/2020')
) t
WHERE rn = 1

Combine ContainerID row and add Qty

I want to combine Container ID, Date, and add the Qty. This query shows data at the item level. I want it to print data at the order level and sum the "Qty" column.
I can combine rows using excel & pivot tables, but when I run reports for over 3 months, I run out of rows in excel, so I break it up into smaller chunks and add the results. Tedious. There has to be an easier way.
What I am getting:
OrderDate ContainerID Qty
2019-06-03 104922434 1
2019-06-03 104922434 1
2019-06-01 104934958 1
2019-06-01 104934958 1
2019-06-01 104934958 1
What I want:
OrderDate ContainerID Qty
2019-06-03 104922434 2
2019-06-01 104934958 3
My current query:
select
convert(date,oh.ShipTime) as 'OrderDate',
p.ContainerID,
cc.Qty
from dmhost.tblOrderHeader oh
join dmhost.tblContainer c on oh.OrderHeaderID = c.OrderHeaderID
join dmhost.tblPackage p on c.ContainerID = p.ContainerID
join dmhost.tblContainerContents cc on c.ContainerID = cc.ContainerID
join dmhost.tblItemMaster im on im.ItemMasterID = cc.ItemMasterID
where (oh.ShipTime between '06/1/2019' and '07/1/2019')
and (BusinessUnitCode like '03'or BusinessUnitCode like '04')
and cc.Qty <> 0
order by p.ContainerID
I appreciate the help.
You can use SUM and GROUP BY:
select
convert(date,oh.ShipTime) as 'OrderDate',
p.ContainerID,
SUM(cc.Qty) Qty
from dmhost.tblOrderHeader oh
join dmhost.tblContainer c on oh.OrderHeaderID = c.OrderHeaderID
join dmhost.tblPackage p on c.ContainerID = p.ContainerID
join dmhost.tblContainerContents cc on c.ContainerID = cc.ContainerID
join dmhost.tblItemMaster im on im.ItemMasterID = cc.ItemMasterID
where (oh.ShipTime between '06/1/2019' and '07/1/2019')
and (BusinessUnitCode like '03'or BusinessUnitCode like '04')
and cc.Qty <> 0
group by
convert(date,oh.ShipTime),
p.ContainerID
order by ContainerID

Query using three tables, joining 2, counting records where 2 columns match from 3rd?

I need to find which course offerings are currently full (the number of students enrolled equals the
capacity of the room it is held in)? For each of the course offerings in the results, list its
symbol, number, section number, building, room number, and capacity.
I know the three tables I need to use are these enrolled, courseoffering_of, and location with these inserts:
INSERT INTO enrolled (netID, symbol, number, sectionNumber) VALUES
('aec3', 'CSE', '4503', '01'),
('hc23', 'CSE', '1384', '02'),
('jjc13', 'CSE', '1384', '02'),
('wp4', 'CSE', '1384', '02' );
INSERT INTO courseoffering_of (symbol, `number`, building, room,
sectionNumber) VALUES
('CSE', '4503', 'Butler', '100', '01'),
('CSE', '1384', 'Butler', '103', '01'),
('CSE', '1384', 'Butler', '103', '02'),
('ECE', '4713', 'Old Main', '2830', '01');
INSERT INTO location (building, room, capacity) VALUES
('Butler', '100', 5),
('Butler', '102', 2),
('Butler', '103', 2),
('Old Main', '2830', 6),
('Old Main', '3030', 3);`
I came up with some pseudocode to help me solve it:
1. merge courseoffering_of and location tables
2. count students in each class from enrolled (same number and section number)
3. select where class from enrolled = class from merged table (same number
and section number)
4. compare number of students counted in that class with room capacity
5. if students enrolled = room capacity return the entry from merged table
I have no idea what to do for this query. I originally thought creating a new table from courseoffering_of and location would help, but our teacher wants us to do this all in a single query. I tried an inner join but couldn't figure out how to use it in this situation.
Any help would be greatly appreciated, thank you.
Let's start here:
select symbol,number,sectionNumber, count(*) as count_enrolled
from enrolled
group by symbol,number,sectionNumber
Above query will return how many students were enrolled for each course:
symbol number sectionNumber count_enrolled
CSE 1384 02 3
CSE 4503 01 1
Then we need to find the room capacity:
select c.*,l.capacity
from courseoffering_of c
join location l
on c.building = l.building
and c.room = l.room
The output is:
symbol number building room sectionNumber capacity
CSE 4503 Butler 100 01 5
CSE 1384 Butler 103 01 2
CSE 1384 Butler 103 02 2
ECE 4713 Old Main 2830 01 6
Now it is time to combine those of queries:
select c.*,l.capacity
,a.count_enrolled
from courseoffering_of c
join location l
on c.building = l.building
and c.room = l.room
join
(select symbol,number,sectionNumber, count(*) as count_enrolled
from enrolled
group by symbol,number,sectionNumber) a
on c.symbol = a.symbol
and c.number = a.number
and c.sectionNumber = a.sectionNumber
You will get:
symbol number building room sectionNumber capacity count_enrolled
CSE 4503 Butler 100 01 5 1
CSE 1384 Butler 103 02 2 3
Finally, pick the full courses.
select * from (
select c.*,l.capacity
,a.count_enrolled
from courseoffering_of c
join location l
on c.building = l.building
and c.room = l.room
join
(select symbol,number,sectionNumber, count(*) as count_enrolled
from enrolled
group by symbol,number,sectionNumber) a
on c.symbol = a.symbol
and c.number = a.number
and c.sectionNumber = a.sectionNumber)b
where b.capacity <= b.count_enrolled
Here is the test result:
DB<>Fiddle
Try this:
SELECT c.symbol, c.number, c.sectionNumber FROM
courseoffering_of c
INNER JOIN
location l
ON
l.building = c.building
AND
l.room = c.room
INNER JOIN
enrolled e
ON
e.number = c.number
AND
e.sectionNumber = c.sectionNumber
GROUP BY c.symbol, c.number, c.sectionNumber, l.capacity
HAVING count(*) >= l.capacity
You can try the following query
with CTE_temp1 as
(
select symbol, number, count(number) Total_student, sectionNumber from enrolled
group by symbol, number, sectionnumber
)
,CTE_temp2 as
(
select a.symbol, a.number, a.building, a.room, a.sectionNumber, b.capacity
from course_offering_of a inner join location b
on a.location = b.location
and a.room = b.room
)
select a.symbol, a.number, a.building, a.room, a.sectionNumber
from CTE_temp2 a inner join CTE_temp1 b
on a.symbol = b.symbol
and a.number = b.number
and a.sectionNumber = b.sectionNumber
where a.capacity = b.Total_student

aggregating nested SQL statements to fewer columns

I am trying to aggregate my data and group it with respect to SKU's and the cluster ID associated with that SKU.
My current output brings back roughly 40,000 rows (5 SKU's * 8,000 Stores) however I want just 35.
My code:
SELECT DISTINCT E.*
FROM ALC_ITEM_SOURCE P
RIGHT JOIN
(
SELECT D.* ,SUM(L.ALLOCATED_QTY) AS TOTAL_ALLOCATED
FROM ALC_ITEM_LOC L
RIGHT JOIN
(
SELECT C.*
FROM STORE S,
(
SELECT A.*, B.LOCATION AS STORE_NUMBER
FROM FDT_MAP_CLUSTER_LOCATION B,
(
SELECT DISTINCT SS.ALLOC_CLUSTER_ID, SS.ALLOC_CLUSTER_NAME, SS.SKU
from fdt_maptool_sas_data ss
WHERE SS.SKU IN (1099866,
1099896,
1000898,
1000960,
1000988
)
AND SS.ORDER_NO IS NOT NULL
AND ALLOC_CLUSTER_NAME NOT LIKE '%DC Cluster%'
GROUP BY SS.ALLOC_CLUSTER_ID, SS.ALLOC_CLUSTER_NAME, SS.WORKSHEET_ID, SS.SKU
)A
WHERE B.CLUSTER_ID = A.ALLOC_CLUSTER_ID
AND B.LOCATION_TYPE = 'S'
)C
WHERE S.STORE = C.STORE_NUMBER
AND S.STORE_CLOSE_DATE IS NULL
AND S.DISTRICT NOT IN (997, 998, 999)
AND S.STORE_OPEN_DATE <= SYSDATE
)D
ON L.ITEM_ID = D.SKU
AND L.LOCATION_ID = D.STORE_NUMBER
GROUP BY D.ALLOC_CLUSTER_ID, D.ALLOC_CLUSTER_NAME, D.SKU, D.STORE_NUMBER
)E
ON P.ITEM_ID = E.SKU
AND P.SOURCE_TYPE <> 4
AND P.RELEASE_DATE > '01-FEB-2018'
My desired result would contain:
SKU Cluster_ID Total_allocated Count(stores)
1000989 1AA STORES 258 200
1000989 2A STORES 78 600
1000989 B STORES 36 500
1000989 C STORES 114 100
1000989 D STORES 144 1222
1000989 E STORES 168 600
1000989 F STORES 60 501
Which is taking a sum of total allocated per store per cluster ID.
As you can see each SKU has a grade (AA-F), I would want to repeat this 5 times since I have 5 SKU's.
Basically I am asking how can I aggregate my data up to look like the above table from the 40,000 rows it is now.
Any help is appreciated!
Just to make your sql nicer and neat, you should avoid constructing joins in 'where' statement.
Also I think you have nothing to do with ALC_ITEM_SOURCE table, since you did not use it practically.
You may try this version, or at least start working on it:
select SS.ALLOC_CLUSTER_ID,SS.ALLOC_CLUSTER_NAME,SS.SKU,SUM (L.ALLOCATED_QTY) as total_allocated,count(b.location) as store_number
FROM fdt_maptool_sas_data ss
inner join
FDT_MAP_CLUSTER_LOCATION b on B.CLUSTER_ID =A.ALLOC_CLUSTER_ID AND B.LOCATION_TYPE = 'S'
inner join store s on S.STORE = b.location AND S.STORE_CLOSE_DATE IS NULL AND S.DISTRICT NOT IN (997, 998, 999) AND S.STORE_OPEN_DATE <= SYSDATE
left outer join ALC_ITEM_LOC L on L.ITEM_ID = ss.SKU AND L.LOCATION_ID = b.location
WHERE SS.SKU IN (1099866,
1099896,
1000898,
1000960,
1000988)
AND SS.ORDER_NO IS NOT NULL
AND ALLOC_CLUSTER_NAME NOT LIKE '%DC Cluster%'

Best SQL for this query

EDIT: So to make it easier we have two tables we need for this query.
1) Account_Cycle_Activity
2) Card_Account
The five columns we will be analyzing from 1) table are.
ACCOUNT_ID
ACTIVITY_TYPE_CDE
CYCLE_CTR
ACTIVITY_GROUP_CODE
CYCLE_ACTIVITY_COUNT
and the column required to know from 2) table are
ACCOUNT_ID
CYCLE_CTR
The logic is:
In ACCOUNT_CYCLE_ACTIVITY table find a row with ACTIVITY_TYPE_CODE = '007' OR '011' OR '021' and ACTIVITY_GROUP_CODE = 'R12' and CYCLE_ACTIVITY_AMOUNT greater than $25 and CYCLE_ACTIVITY_COUNT between 1 to 900 -- This is the first clause of my query.
And for the row which we just found above, its CYCLE_CTR column should be equal to the CYCLE_CTR column value from CARD_ACCOUNT table CYCLE_CTR minus 1. -- This is the second clause
Now this is the EXIST part of query
If you find a row like this, and there are also no rows in the table for the same ACCOUNT_ID with the same ACTIVITY_TYPE_CODE and same ACTIVITY_GROUP_CODE and CYCLE_ACTIVITY_COUNT = 1 with CYCLE_CTR anywhere between the first row's CYCLE_CTR -6 through the first row's CYCLE_CTR - 1, report the account.
I came up with the below query
SELECT *
FROM ACCOUNT_CYCLE_ACTIVITY aca
inner join card_account ca on ca.account_id = aca.ACCOUNT_ID
WHERE ACTIVITY_TYPE_CODE in('011', '021', '007')
and ACTIVITY_GROUP_CODE= 'R12'
and (CYCLE_ACTIVITY_AMOUNT) > 25
and CYCLE_ACTIVITY_COUNT =1
and aca.cycle_ctr = ca.cycle_ctr - 1
and NOT EXISTS
(SELECT aca2.ACCOUNT_ID
FROM ACCOUNT_CYCLE_ACTIVITY aca2
where ca.account_id = aca2.ACCOUNT_ID
and aca2.ACTIVITY_TYPE_CODE=aca.activity_type_code
and aca2.ACTIVITY_GROUP_CODE= aca.activity_group_code
and CYCLE_ACTIVITY_COUNT =1
and aca2.cycle_ctr between aca.cycle_ctr - 6 and aca.cycle_ctr - 1);
Any ides on how to write it more efficiently to improve running time?
try a left (outer) join
SELECT aca.*, ca.*
FROM card_account ca
inner join ACCOUNT_CYCLE_ACTIVITY aca
on aca.account_id = ca.ACCOUNT_ID
and aca.ACTIVITY_TYPE_CODE in ('011', '021', '007')
and aca.ACTIVITY_GROUP_CODE = 'R12'
and aca.CYCLE_ACTIVITY_COUNT = 1
and aca.cycle_ctr = ca.cycle_ctr - 1
and aca.CYCLE_ACTIVITY_AMOUNT > 25
left join ACCOUNT_CYCLE_ACTIVITY aca2
on aca2.account_id = aca.ACCOUNT_ID
and aca2.ACTIVITY_TYPE_CODE = aca.activity_type_code
and aca2.ACTIVITY_GROUP_CODE = aca.activity_group_code
and aca2.CYCLE_ACTIVITY_COUNT = aca.CYCLE_ACTIVITY_COUNT
and aca2.cycle_ctr between aca.cycle_ctr - 6 and aca.cycle_ctr - 1
where aca2.ACCOUNT_ID is null