Select the sum of a count in select statement where date between - database

I have a query that select the count of data from each day, I want to modify the query so it can get the data from a date between two dates
The first Query as follows:
SELECT ROW_NUMBER() OVER (ORDER BY q.english_Name DESC) as id,
COUNT(t.id) AS ticket,
q.english_name queue_name,
ts.code current_status,
COUNT(t.assigned_to) AS assigned,
(COUNT(t.id)-COUNT(t.assigned_to)) AS not_assigned
,trunc(t.create_date) create_Date
FROM ticket t
INNER JOIN ref_queue q
ON (q.id = t.queue_id)
INNER JOIN ref_ticket_status ts
ON(ts.id=t.current_status_id)
GROUP BY q.english_name,
ts.code
,trunc(t.create_date)
but when I modify it to :
SELECT ROW_NUMBER() OVER (ORDER BY q.english_Name DESC) as id,
COUNT(t.id) AS ticket,
q.english_name queue_name,
ts.code current_status,
COUNT(t.assigned_to) AS assigned,
(COUNT(t.id)-COUNT(t.assigned_to)) AS not_assigned
,trunc(t.create_date) create_Date
FROM ticket t
INNER JOIN ref_queue q
ON (q.id = t.queue_id)
INNER JOIN ref_ticket_status ts
ON(ts.id=t.current_status_id)
where t.create_date between '18-FEB-19' and '24-FEB-19'
GROUP BY q.english_name,
ts.code
,trunc(t.create_date)
the output is
1 1 Technical Support Sec. CLOSED 0 1 19-FEB-19
2 6 Technical Support Sec. OPEN 4 2 18-FEB-19
3 1 Technical Support Sec. OPEN 0 1 21-FEB-19
4 3 Network Sec. OPEN 2 1 18-FEB-19
5 1 Network Sec. OPEN 0 1 21-FEB-19
how can i get the total output of the days so that the output is:
1 7 Technical Support Sec. OPEN 4 3
2 4 Network Sec. OPEN 2 2

When you GROUP BY in a query, your result set will include one row for every distinct set of values in your GROUP BY list. For example, the reason you are getting two rows for the OPEN records for "Techical Support Sec" is because there are two distinct values for TRUNC(t.create_date) resulting in two groups and, therefore, two rows in your result set.
To avoid that, stop grouping by TRUNC(t.create_date).
SELECT ROW_NUMBER() OVER (ORDER BY q.english_Name DESC) as id,
COUNT(t.id) AS ticket,
q.english_name queue_name,
ts.code current_status,
COUNT(t.assigned_to) AS assigned,
(COUNT(t.id)-COUNT(t.assigned_to)) AS not_assigned
-- ,trunc(t.create_date) create_Date
FROM ticket t
INNER JOIN ref_queue q
ON (q.id = t.queue_id)
INNER JOIN ref_ticket_status ts
ON(ts.id=t.current_status_id)
where t.create_date between '18-FEB-19' and '24-FEB-19'
GROUP BY q.english_name,
ts.code
-- ,trunc(t.create_date)

Related

Join in SQL Server when some query doesn't have results

I have a table with stock product movements (MOVSTOCKS) in two warehouses (CodAlm). For simplify the question, I will focus on a single product (with CodArt = C5):
CodArt
DescArt
CodAlm
UnidadesStock
EntranStock
SalenStock
FecDoc
TipDoc
C5
Palet
1
16
16
0
2021-12-31
IN
C5
Palet
2
0
0
0
2021-12-31
IN
C5
Palet
1
3
0
3
2022-01-11
SL
C5
Palet
1
4
0
4
2022-01-20
SL
C5
Palet
1
7
7
0
2022-02-01
EN
C5
Palet
1
6
0
6
2022-02-14
SL
C5
Palet
1
9
9
10
2022-05-01
IN
C5
Palet
2
1
1
0
2022-05-01
IN
C5
Palet
1
2
0
2
2022-06-10
SL
I need to get the stock on a certain day. For this, is necessary obtain stock quantity of the last inventory (TipDoc = IN) and add it purchases quantities (TipDoc = EN) and subtract the sales (TipDoc = SL).
I tried this query:
SELECT MV.CODART, MV.DESCART, MV.CODALM, SC.UNIDADESSTOCK + SUM(MV.ENTRANSTOCK) - SUM(MV.SALENSTOCK) as STOCK
FROM MOVSTOCKS MV
JOIN ( SELECT MV1.CODART, MV1.CODALM, MV2.FECDOC, MV1.UNIDADESSTOCK
FROM MOVSTOCKS MV1
JOIN ( SELECT CODART, CODALM, MAX(FECDOC) FECDOC
FROM MOVSTOCKS
WHERE TIPDOC = 'IN'
GROUP BY CODART, CODALM) MV2
ON MV1.CODART = MV2.CODART AND MV1.CODALM = MV2.CODALM AND MV1.FECDOC = MV2.FECDOC
WHERE MV1.TIPDOC = 'IN' ) SC
ON MV.CODART = SC.CODART AND MV.CODALM = SC.CODALM AND MV.FECDOC > SC.FECDOC
WHERE MV.CODART = 'C5' and MV.FECDOC <= '2022-06-01'
GROUP BY MV.CODART, MV.DESCART, MV.CODALM, SC.UNIDADESSTOCK
ORDER BY MV.CODART, MV.CODALM
With above data example and the query I expected to get following results:
CodArt
DescArt
CodAlm
Stock
C5
Palet
1
9
C5
Palet
2
1
The problem is that after the last inventory (2022-05-01) there have been no movements and then the join query get 0 rows because the filter MV.FECDOC <= '2022-06-01' in the WHERE doesn't get rows. I could modify the 'ON' condition in the join to MV.FECDOC >= SC.FECDOC and then get at least the inventory row, but I shouldn't do that because on inventory day there might be other previous movements that I shouldn't get for stock calculation.
Moreover, I will have the same problem if I want to get stock in a date for a product without inventory movements, because subquery 'SC' won't get rows.
Any help, please?
If you know that the inventory records exist, but the other transaction records might or might not exist afterwards, you will need to select your inventory records first and then LEFT JOIN the other transaction records.
If we only had to select one inventory record, we could start with a SELECT TOP 1 * ... ORDER BY FECDOC DESC with appropriate additional conditions. However, to get the latest inventory record for each of multiple warehouses, it get a bit more complicated. Two approaches that come to mind.
One would be to first select distinct warehouse codes (or perhaps distinct warehouse and product codes) and then CROSS APPLY a subselect to retrieve the latest inventory record for each.
The other approach would be to use the ROW_NUMBER() window function to number the inventory records by descending date (partitioned by warehouse codes and product codes) and then exclude all but row number = 1.
In either case, the next step would be to LEFT JOIN the transaction records, apply a GROUP BY, and SUM() up the results. Since SUM() returns NULL if there are no elements to sum, we need to use the ISNULL() function to assign a default value of zero.
The following two similar queries demonstrate the above approaches.
DECLARE #CODART VARCHAR(10) = 'C5'
DECLARE #AsOfDate DATETIME2 = '2022-06-01'
-- Method 1: SELECT DISTINCT followed by a cross apply
SELECT
SC.CODART, SC.DESCART, SC.CODALM,
SC.UNIDADESSTOCK + ISNULL(SUM(MV2.ENTRANSTOCK), 0) - ISNULL(SUM(MV2.SALENSTOCK), 0) as STOCK
FROM (
SELECT DISTINCT MV.CODART, MV.CODALM
FROM #MOVSTOCKS MV
WHERE MV.CODART = #CODART
) A
CROSS APPLY (
-- Most recent inventory for each selected CODART, CODALM
SELECT TOP 1 MV1.*
FROM #MOVSTOCKS MV1
WHERE MV1.CODART = A.CODART
AND MV1.CODALM = A.CODALM
AND MV1.TIPDOC = 'IN'
AND MV1.FECDOC <= #AsOfDate
ORDER BY MV1.FECDOC DESC
) SC
LEFT JOIN #MOVSTOCKS MV2
ON MV2.CODART = SC.CODART
AND MV2.CODALM = SC.CODALM
AND MV2.TIPDOC IN ('EN', 'SL')
AND MV2.FECDOC > SC.FECDOC
AND MV2.FECDOC <= #AsOfDate
GROUP BY SC.CODART, SC.DESCART, SC.CODALM, SC.UNIDADESSTOCK
ORDER BY SC.CODART, SC.CODALM
-- Method 2: Using the ROW_NUMBER() window function
SELECT
SC.CODART, SC.DESCART, SC.CODALM,
SC.UNIDADESSTOCK + ISNULL(SUM(MV2.ENTRANSTOCK), 0) - ISNULL(SUM(MV2.SALENSTOCK), 0) as STOCK
FROM (
-- Most recent inventory at or before #AsOfDate will have Recency = 1
SELECT MV1.*,
ROW_NUMBER() OVER(PARTITION BY CODART, CODALM ORDER BY FECDOC DESC) AS Recency
FROM #MOVSTOCKS MV1
WHERE MV1.FECDOC <= #AsOfDate
AND MV1.TIPDOC = 'IN'
) SC
LEFT JOIN #MOVSTOCKS MV2
ON MV2.CODART = SC.CODART
AND MV2.CODALM = SC.CODALM
AND MV2.FECDOC > SC.FECDOC
AND MV2.FECDOC <= #AsOfDate
AND MV2.TIPDOC IN ('EN', 'SL')
WHERE SC.Recency = 1
AND SC.CODART = #CODART
GROUP BY SC.CODART, SC.DESCART, SC.CODALM, SC.UNIDADESSTOCK
ORDER BY SC.CODART, SC.CODALM
Both queries above produce the desired result. See this db<>fiddle for a working demo.
*** UPDATE *** To handle cases where we might have transactions (added stock and/or sales) but no prior reference inventory, we will need to assume an initial inventory of zero and include all transactions since the beginning-of-time (start or data). This also requires making the initial SELECT DISTINCT the primary source for product and warehouse information. The CROSS APPLY becomes an OUTER APPLY (similar to a LEFT JOIN) and we need to make other adjustments to handle a possible null inventory record. That includes adjusting the date range for the transaction join.
The updated query would be something like:
SELECT
A.CODART, A.DESCART, A.CODALM,
ISNULL(SC.UNIDADESSTOCK, 0) + ISNULL(SUM(MV2.ENTRANSTOCK), 0) - ISNULL(SUM(MV2.SALENSTOCK), 0) as STOCK
, SC.UNIDADESSTOCK AS PriorInventory
, SUM(MV2.ENTRANSTOCK) AS NewStock
, SUM(MV2.SALENSTOCK) as Sales
FROM (
SELECT DISTINCT MV.CODART, MV.DESCART, MV.CODALM
FROM #MOVSTOCKS MV
WHERE MV.CODART = #CODART
) A
OUTER APPLY (
-- Most recent inventory for each selected CODART, CODALM combination
SELECT TOP 1 MV1.*
FROM #MOVSTOCKS MV1
WHERE MV1.CODART = A.CODART
AND MV1.CODALM = A.CODALM
AND MV1.TIPDOC = 'IN'
AND MV1.FECDOC <= #AsOfDate
ORDER BY MV1.FECDOC DESC
) SC
LEFT JOIN #MOVSTOCKS MV2
-- Transactions since inventory was last recorded
ON MV2.CODART = A.CODART
AND MV2.CODALM = A.CODALM
AND MV2.TIPDOC IN ('EN', 'SL') -- Alternately <> 'IN' or omitted entirely.
AND MV2.FECDOC > ISNULL(SC.FECDOC, '1900-01-01')
AND MV2.FECDOC <= #AsOfDate
GROUP BY A.CODART, A.DESCART, A.CODALM, SC.UNIDADESSTOCK
ORDER BY A.CODART, A.CODALM
See this db<>fiddle for an updated demo. For this demo, I added a new stock record for warehouse 3 and set the #AsOfDate to '2022-12-31'. I also added details to the result showing the separate initial inventory, new stock, and sales that feed the final STOCK calculation.
CODART
DESCART
CODALM
STOCK
PriorInventory
NewStock
Sales
C5
Palet
1
7
9
0
2
C5
Palet
2
1
1
null
null
C5
Palet
3
6
null
6
0
The above includes cases having inventory with transactions, inventory but no transactions, and transactions with no initial inventory.
I abandoned the ROW_NUMBER() alternate approach.

SQL Query Get Last record Group by multiple fields

Hi I have a table with following fields:
ALERTID POLY_CODE ALERT_DATETIME ALERT_TYPE
I need to query above table for records in the last 24 hour.
Then group by POLY_CODE and ALERT_TYPE and get the latest Alert_Level value ordered by ALERT_DATETIME
I can get up to this, but I need the AlertID of the resulting records.
Any suggestions what would be an efficient way of getting this ?
I have created an SQL in SQL Server. See below
SELECT POLY_CODE, ALERT_TYPE, X.ALERT_LEVEL AS LAST_ALERT_LEVEL
FROM
(SELECT * FROM TableA where ALERT_DATETIME >= GETDATE() -1) T1
OUTER APPLY (SELECT TOP 1 [ALERT_LEVEL]
FROM (SELECT * FROM TableA where ALERT_DATETIME >= GETDATE() -1) T2
WHERE T2.POLY_CODE = T1.POLY_CODE AND
T2.ALERT_TYPE = T1.ALERT_TYPE ORDER BY T2.[ALERT_DATETIME] DESC) X
GROUP BY POLY_CODE, ALERT_TYPE, X.[ALERT_LEVEL]
POLY_CODE ALERT_TYPE ALERT_LEVEL
04575 Elec 2
04737 Gas 3
06239 Elec 2
06552 Elec 2
06578 Elec 2
10320 Elec 2
select top 1 with ties *
from TableA
where ALERT_DATETIME >= GETDATE() -1
order by row_number() over (partition by POLY_CODE,ALERT_TYPE order by [ALERT_DATETIME] DESC)
The way this works is that for each group of POLY_CODE,ALERT_TYPE get their own row_number() starting from the most recent alert_datetime. Then, the with ties clause ensures that all rows(= all groups) with the row_number value of 1 get returned.
One way of doing it is creating a cte with the grouping that calculates the latesdatetime for each and then crosses it with the table to get the results. Just keep in mind that if there are more than one record with the same combination of poly_code, alert_type, alert_level and datetime they will all show.
WITH list AS (
SELECT ta.poly_code,ta.alert_type,MAX(ta.alert_datetime) AS LatestDatetime,
ta.alert_level
FROM dbo.TableA AS ta
WHERE ta.alert_datetime >= DATEADD(DAY,-1,GETDATE())
GROUP BY ta.poly_code, ta.alert_type,ta.alert_level
)
SELECT ta.*
FROM list AS l
INNER JOIN dbo.TableA AS ta ON ta.alert_level = l.alert_level AND ta.alert_type = l.alert_type AND ta.poly_code = l.poly_code AND ta.alert_datetime = l.LatestDatetime

Get's records where gap between two dates is less than or equal to 5 days

I have two tables: tickets with unique ticket id and tickethistory with multiple records of a ticket (like open,attend,forward,close etc). Want to get records of
customers whose current ticket is open and last closed ticket is within 5 days gap. Using following query gives multiple records of closed tickets. Want last closed ticket actiondate in order to calculate days gap. If current open ticket and last closed ticket are within 5 days gap, want to consider current ticket as repeated.
SELECT A.ticketId,A.username,A.status,A.areaName,A.subject
,d.deptId,d.action,d.actionDate odate,g.actionDate cdate,g.status
FROM tb_tickets A
INNER JOIN (SELECT action, actiondate, ticketId, deptId FROM tb_ticketHistory WHERE action='Open') d
on a.ticketId = d.ticketid
INNER JOIN (SELECT th.ticketid, tt.username, tt.status, actiondate FROM tb_ticketHistory th
INNER JOIN tb_tickets tt
on th.ticketId = tt.ticketId WHERE th.action='closed') g
on a.username = g.username
WHERE d.deptId=5 AND a.status!='closed'
ORDER BY ticketId ASC
Since you haven't give exact structure and sample data, it's tough to give an exact answer. but you can try following code by tweaking it as your structure -
select CurrentOpenTickets.customerid, CurrentOpenTickets.ticketid from
(
select customerid, t.ticketid, actiondate from [dbo].[tb_ticketHistory ] th
inner join [dbo].[tb_Tickets] t on t.ticketid = th.ticketid
where t.status != 'C'
) CurrentOpenTickets
inner join
(select customerid, t.ticketid, actiondate from [dbo].[tb_ticketHistory ] th
inner join [dbo].[tb_Tickets] t on t.ticketid = th.ticketid
where th.status = 'C'
) PastClosedTickets
on CurrentOpenTickets.customerid = PastClosedTickets.customerid and datediff(DAY, CurrentOpenTickets.actiondate, PastClosedTickets.actiondate) <= 5

remove duplicates based on column in inner join

This is returning exactly what I want, except some rows need to be removed because the inner join has matched multiple rows when I only want it to match the first match.
select table1.IDa, table1.IDb, table1.name,
table1b.IDa, table1b.IDb, table1b.name
from
(select IDa,IDb,name from mytable) table1
inner join
(select IDa,IDb,name from mytable) table1b
ON
table1.IDa = table1b.IDa
and table1.IDb = table1b.IDb
order By table1.IDa
So I'm getting this:
IDa IDb name IDa IDb name
1 1 bob 1 1 public
1 1 bob 1 1 smith
1 2 sally 1 2 jones
2 1 nancy 2 1 dole
But I want to receive this:
IDa IDb name IDa IDb name
1 1 bob 1 1 public
1 2 sally 1 2 jones
2 1 nancy 2 1 dole
I only want the first match for the IDa+IDb combination returned.
Based on asker's comment
That would be the oldest entry into the database, it would also be the
same as order by IDa,IDb. It would also be the first match seen in the
returned results
Try this query :
select table1.IDa, table1.IDb, table1.name,
table1b.IDa, table1b.IDb, table1b.name
from
(select IDa,IDb,name from mytable) table1
inner join
(select IDa,IDb,name, ROW_NUMBER() OVER( ORDER BY Ida,IDb) as r from mytable ) table1b
ON
table1.IDa = table1b.IDa
and table1.IDb = table1b.IDb
and table1b.r=1
order By table1.IDa
As per your comments this should work, But Smith and Public has same IDa and IDb values hope it is data issue.
;WITH cte
AS (SELECT rn=Row_number()OVER(partition BY table1b.name ORDER BY table1.IDa, table1.IDb),
table1.IDa AS t1_ida,
table1.IDb AS t1_idb,
table1.name AS t1_name,
table1b.IDa AS t2_ida,
table1b.IDb AS t2_idb,
table1b.name AS t2_name
FROM mytable table1
INNER JOIN mytable table1b
ON table1.IDa = table1b.IDa
AND table1.IDb = table1b.IDb)
SELECT *
FROM cte
WHERE rn = 1

Counting duplicate items in different order

Goal:
To know if we have purchased duplicate StockCodes or Stock Description more than once on difference purchase orders
So, if we purchase Part ABC on Purchase Order 1 and Purchase Order 2, it should return the result of
PurchaseOrders, Part#, Qty
Purchase Order1, Purchase Order2, ABC, 2
I just don't know how to pull the whole code together, more to the point, how do I know if it's occurred on more than 1 Purchase Order without scrolling through all the results , may also have to do with Multiple (Having Count) Statements as I only seem to be doing by StockCode
SELECT t1.PurchaseOrder,
t1.MStockCode,
Count(t1.MStockCode) AS SCCount,
t1.MStockDes,
Count(t1.MStockDes) AS DescCount
FROM PorMasterDetail t1
INNER JOIN PorMasterHdr t2
ON t1.PurchaseOrder = t2.PurchaseOrder
WHERE Year(t2.OrderEntryDate) = Year(Getdate())
AND Month(t2.OrderEntryDate) = Month(Getdate())
GROUP BY t1.PurchaseOrder,
t1.MStockCode,
t1.MStockDes
HAVING Count(t1.MStockCode) > 1
Using responses I came up with the following
select * from
(
SELECT COUNT(dbo.InvMaster.StockCode) AS Count, dbo.InvMaster.StockCode AS StockCodes,
dbo.PorMasterDetail.PurchaseOrder, dbo.PorMasterHdr.OrderEntryDate
FROM dbo.InvMaster INNER JOIN dbo.PorMasterDetail ON
dbo.InvMaster.StockCode = dbo.PorMasterDetail.MStockCode
INNER JOIN dbo.PorMasterHdr ON dbo.PorMasterDetail.PurchaseOrder = dbo.PorMasterHdr.PurchaseOrder
WHERE YEAR(dbo.PorMasterHdr.OrderEntryDate) = YEAR(GETDATE())
GROUP BY dbo.InvMaster.StockCode, dbo.InvMaster.StockCode,
dbo.PorMasterDetail.PurchaseOrder, dbo.PorMasterHdr.OrderEntryDate
) Count
Where Count.Count > 1
This returns the below , which is starting to be a bit more helpful
In result line 2,3,4 we can see the same stock code (*30044) ordered 3 times on different
purchase orders.
I guess the question is, is it possible to look at If something was ordered more than once within say a 30 day period.
Is this possible?
Count StockCodes PurchaseOrder OrderEntryDate
2 *12.0301.0021 322959 2014-09-08
2 *30044 320559 2014-01-21
8 *30044 321216 2014-03-26
4 *30044 321648 2014-05-08
5 *32317 321216 2014-03-26
4 *4F-130049/TEST 323353 2014-10-22
5 *650-1157/E 322112 2014-06-24
2 *650-1757 321226 2014-03-27
SELECT *
FROM
(
SELECT h.OrderEntryDate, d.*,
COUNT(*) OVER (PARTITION BY d.MStockCode) DupeCount
FROM
PorMasterHdr h
INNER JOIN PorMasterDetail d ON
d.PurchaseOrder = h.PurchaseOrder
WHERE
-- first day of current month
-- http://blog.sqlauthority.com/2007/05/13/sql-server-query-to-find-first-and-last-day-of-current-month/
h.OrderEntryDate >= CONVERT(VARCHAR(25), DATEADD(dd,-(DAY(GETDATE())-1),GETDATE()),101)
) dupes
WHERE
dupes.DupeCount > 1;
This should work if you're only deduping on stock code. I was a little unclear if you wanted to dedupe on both stock code and stock desc, or either stock code or stock desc.
Also I was unclear on your return columns because it almost looks like you're wanting to pivot the columns so that both purchase order numbers appear on the same line.

Resources