SQL Server - SELECT statement with Variable and SUM() method - sql

EDIT:
Will try to explain in more detail this time as best as I can. I tried to make the query a bit simpler thinking it would make it easier to understand but it might have been a bad move.
I'm trying to get the PK_Queue and FK_Queue_Milestone from the 1st row of my Queue table ordered by PriorityScore DESC and TimeAdded ASC
I only want to get the first row, but I was advised to not use TOP(1) because it would result to another SELECT being made to my original select.
This is the query that I have:
SELECT
#Local_PK_Queue = Q.PK_Queue,
#Local_PK_Milestone_Validate = Q.FK_Queue_Milestone
FROM dbo.Queue AS Q
INNER JOIN #Local_PKHolderTable AS P
ON Q.FK_Queue_Process = P.PK_Process
AND Q.FK_Queue_Milestone = P.PK_Milestone
AND Q.FK_Queue_QueueType = P.PK_QueueType
WHERE Q.FK_Queue_Milestone = P.PK_Milestone
AND Q.FK_Queue_Process = P.PK_Process
AND Q.Tags LIKE '%' + #Input_Tags + '%'
AND ((FK_Queue_State = 5 AND TimeDeferred < GETUTCDATE()) OR (FK_Queue_State = 1))
AND Q.FK_Queue_Robot IS NULL
AND Q.FK_Queue_QueueType = P.PK_QueueType
ORDER BY
Q.PriorityScore DESC,
Q.TimeAdded
When I try to run the query, it doesn't seem to be ordering it properly because it always gets the last row of my table.
So did some research and stumbled upon this question here.
It seems to be the same problem that I am experiencing but using MySQL instead of SQL Server.
TLDR: Want to ORDER BY Priority Score DESC and TimeAdded, but is not working properly

Well, you would write this as:
SELECT #var = PK_Test, #var2 = SUM(PriorityScore)
FROM Queue
GROUP BY PK_Test
ORDER BY SUM(PriorityScore);
This is very strange, though, because the GROUP BY presumably returns multiple rows and you presumably want only one. I might suspect that you really want to assign the variables to the highest priority scores:
SELECT TOP (1) #var = PK_Test, #var2 = SUM(PriorityScore)
FROM Queue
GROUP BY PK_Test
ORDER BY SUM(PriorityScore) DESC;

Related

Agregating a subquery

I try to find what I missed in the code to retrieve the value of "Last_Maintenance" in a table called "Interventions".
I try to understand the order rules of SQL and the particularities of subqueries without success.
Did I missed something, something basic or an important step?
---Interventions with PkState "Schedule_Visit" with the Last_Maintenance aggregation
SELECT Interventions.ID AS Nro_Inter,
--Interventions.PlacesList AS Nro_Place,
MaintenanceContracts.Num AS Nro_Contract,
Interventions.TentativeDate AS Schedule_Visit,
--MaintenanceContracts.NumberOfVisits AS Number_Visits_Contracts,
--Interventions.VisitNumber AS Visit_Number,
(SELECT MAX(Interventions.AssignmentDate)
FROM Interventions
WHERE PkState = 'AE4B42CF-0003-4796-89F2-2881527DFB26' AND PkMaintenanceContract IS NOT NULL) AS Last_Maintenance --PkState "Maintenance Executed"
FROM Interventions
INNER JOIN MaintenanceContracts ON MaintenanceContracts.Pk = Interventions.PkMaintenanceContract
WHERE PkState = 'AE4B42CF-0000-4796-89F2-2881527ABC26' AND PkMaintenanceContract IS NOT NULL --PkState "Schedule_Visit"
GROUP BY Interventions.AssignmentDate,
Interventions.ID,
Interventions.PlacesList,
MaintenanceContracts.Num,
Interventions.TentativeDate,
MaintenanceContracts.NumberOfVisits,
Interventions.VisitNumber
ORDER BY Nro_Contract
I try to use GROUP BY and HAVING clause in a sub query, I did not succeed. Clearly I am lacking some understanding.
Output
The output of "Last_Maintenance" is the last date of entire contracts in the DB, which is not the desirable output. The desirable output is to know the last date the maintenance was executed for each row, meaning, for each "Nro-Contract". Somehow I need to aggregate like I did below.
In opposition of what mention I did succeed in another table.
In the table Contracts I did had success as you can see.
SELECT
MaintenanceContracts.Num AS Nro_Contract,
MAX(Interventions.AssignmentDate) AS Last_Maintenance
--MaintenanceContracts.Name AS Place
--MaintenanceContracts.StartDate,
--MaintenanceContracts.EndDate
FROM MaintenanceContracts
INNER JOIN Interventions ON Interventions.PkMaintenanceContract = MaintenanceContracts.Pk
WHERE MaintenanceContracts.ActiveContract = 2 OR MaintenanceContracts.ActiveContract = 1 --// 2 = Inactive; 1 = Active
GROUP BY MaintenanceContracts.Num, MaintenanceContracts.Name,
MaintenanceContracts.StartDate,
MaintenanceContracts.EndDate
ORDER BY Nro_Contract
I am struggling to understanding how nested queries works and how I can leverage in a simple manner the queries.
I think you're mixed up in how aggregation works. The MAX function will get a single MAX value over the entire dataset. What you're trying to do is get a MAX for each unique ID. For that, you either use derived tables, subqueries or windowed functions. I'm a fan of using the ROW_NUMBER() function to assign a sequence number. If you do it correctly, you can use that row number to get just the most recent record from a dataset. From your description, it sounds like you always want to have the contract and then get some max values for that contract. If that is the case, then you're second query is closer to what you need. Using windowed functions in derived queries has the added benefit of not having to worry about using the GROUP BY clause. Try this:
SELECT
MaintenanceContracts.Num AS Nro_Contract,
--MaintenanceContracts.Name AS Place
--MaintenanceContracts.StartDate,
--MaintenanceContracts.EndDate
i.AssignmentDate as Last_Maintenance
FROM MaintenanceContracts
INNER JOIN (
SELECT *
--This fuction will order the records for each maintenance contract.
--The most recent intervention will have a row_num = 1
, ROW_NUMBER() OVER(PARTITION BY PkMaintenanceContract ORDER BY AssignmentDate DESC) as row_num
FROM Interventions
) as i
ON i.PkMaintenanceContract = MaintenanceContracts.Pk
AND i.row_num = 1 --Used to get the most recent intervention.
WHERE MaintenanceContracts.ActiveContract = 2
OR MaintenanceContracts.ActiveContract = 1 --// 2 = Inactive; 1 = Active
ORDER BY Nro_Contract
;

how to filter record which contains exactly two values in a table in sql?

When I use IN, it shows all records contains parameter1 or parameter2, but I want it bring to records contains exactly both of them, not just one of them.
If my question is not clear, I can try to explain again.
select Hatlar.Name
from HATLAR,
[HAT-DURAK],
DURAKLAR
where HATLAR.Hat_Id = [HAT-DURAK].Hat_Id
and DURAKLAR.Durak_Id = [HAT-DURAK].Durak_Id
and DURAKLAR.Name IN ('parameter1', 'parameter2')
Do a GROUP BY. Use having count distinct to make sure both DURAKLAR.Names are there.
select Hatlar.Name
from HATLAR,
[HAT-DURAK],
DURAKLAR
where HATLAR.Hat_Id = [HAT-DURAK].Hat_Id
and DURAKLAR.Durak_Id = [HAT-DURAK].Durak_Id
and DURAKLAR.Name IN ('parameter1', 'parameter2')
group by Hatlar.Name
having count(distinct DURAKLAR.Name) = 2
First, learn to use proper JOIN syntax. Commas in the FROM clause are soooo 20th century.
Second, you can do what you want with GROUP BY and HAVING:
Select h.Name
from HATLAR h join
[HAT-DURAK] hd
on h.Hat_Id = hd.Hat_Id join
DURAKLAR d
on d.Durak_Id = d.Durak_Id
where d.Name IN ('parameter1', 'parameter2')
group by n.Name
having count(d.Name) = 2;
Note: If duplicates can appear in the junction table, then use count(distinct d.Name).
If I understand the question, this should work (assuming the parameters are actually that, and not hard coded strings):
select Hatlar.Name
from HATLAR,
[HAT-DURAK],
DURAKLAR
where HATLAR.Hat_Id = [HAT-DURAK].Hat_Id
and DURAKLAR.Durak_Id = [HAT-DURAK].Durak_Id
and DURAKLAR.Name Like '%' + #parameter1 + '%'
and DURAKLAR.Name Like '%' + #parameter2 + '%'

SQL Statement to select row where previous row status = 'C' AS400

This is being run on sql for IBMI Series 7
I have a table which stores info about orders. Each row has an order number (ON), part number(PN), and sequence number(SEQ). Each ON will have multiple PN's linked to them and each part number has multiple SEQ Number. Each sequence number represents the order in which to do work on the part. Somewhere else in the system once the part is at a location and ready to be worked on it shows a flag. What I want to do is get a list of orders for a location that have not yet arrived but have been closed out on the previous location( Which means the part is on it's way).
I have a query listed below that I believe should work but I get the following error: "The column qualifier or table t undefined". Where is my issue at?
Select * From (SELECT M2ON as Order__Number , M2SEQ as Sequence__Number,
M2PN as Product__Number,ML2OQ as Order__Quantity
FROM M2P
WHERE M2pN in (select R1PN FROM R1P WHERE (RTWC = '7411') AND (R1SEQ = M2SEQ)
)
AND M2ON IN (SELECT M1ON FROM M1P WHERE ML1RCF = '')
ORDER BY ML2OSM ASC) as T
WHERE
T.Order__Number in (Select t3.m2on from (SELECT *
FROM(Select * from m2p
where m2on = t.Order__Number and m2pn = t.Product__Number
order by m2seq asc fetch first 2 rows only
)as t1 order by m2seq asc fetch first row only
) as t3 where t3.m2stat = 'C')
EDIT- Answer for anyone else with this issue
Clutton's Answer worked with slight modification so thank you to him for the fast response! I had to name my outer table and specify that in the subquery otherwise the as400 would kick back and tell me it couldn't find the columns. I also had to order by the sequence number descending so that I grabbed the highest record that was below the parameter(otherwise for example if my sequence number was 20 it could grab 5 even though 10 was available and should be shown first. Here is the subquery I now use. Please note the actual query names m2p as T1.
IFNULL((
SELECT
M2STAT
FROM
M2P as M2P_1
WHERE
M2ON = T1.M2ON
AND M2SEQ < T1.M2SEQ
AND M2PN IN (select R1PN FROM R1P WHERE (RTWC = #WC) AND (R1SEQ = T1.M2SEQ))
ORDER BY M2SEQ DESC
FETCH FIRST ROW ONLY
), 'NULL') as PRIOR_M2STAT
Just reading your question, it looks like something I do frequently to emulate RPG READPE op codes. Is the key to M2P Order/Seq? If so, here is a basic piece that may help you build out the rest of the query.
I am assuming that you are trying to get the prior record by key using SQL. In RPG this would be like doing a READPE on the key for a file with Order/Seq key.
Here is an example using a subquery to get the status field of the prior record.
SELECT
M2ON, M2PN, M2OQ, M2STAT,
IFNULL((
SELECT
M2STAT
FROM
M2P as M2P_1
WHERE
M2P_1.M2ON = M2ON
AND M2P_1.M2SEQ < M2SEQ
FETCH FIRST ROW ONLY
), '') as PRIOR_M2STAT
FROM
M2P
Note that this wraps the subquery in an IFNULL to handle the case where it is the first sequence number and no prior sequence exists.

Selecting the last set of records in SQL Server that match certain criteria

I've got 10 records that match the criteria I'm searching for. The problem is there are two sets of 10 records, one at 1pm and one at 3pm. I only want the sets at 3pm. Here's part of my SQL:
select shp_rev.ShpNum, shp_rev.RevTime
from shp_rev
where shp_rev.RevDate = '10/1/2015'
and shp_rev.ValAfter = 'O'
and shp_rev.ShpNum = 732809
(I've added the shp_rev.ShpNum to the where just to narrow down the data to a dataset that has this problem. Normally I wouldn't have that in the where. And there are other fields that would be included with this select.)
This produces:
732809 13:14:45
732809 13:14:45
...
732809 15:23:33
732809 15:23:33
...
I only want the records at 15:23:33. I know one way I can do it is to concatenate all of the fields I want into one string with ShpNum and RevTime at the beginning then using MAX() to get just the 3pm records like this:
select max(cast(shp_rev.ShpNum as varchar) + '~' + shp_rev.RevTime)
from shp_rev
where shp_rev.RevDate = '10/1/2015'
and shp_rev.ValAfter = 'O'
and shp_rev.ShpNum = 732809
order by max(cast(shp_rev.ShpNum as varchar) + '~' + shp_rev.RevTime)
But then I have to parse back that string to get everything. It seems there must be a better way. I've tried using MAX() on ShpNum and RevTime separately but that doesn't work. Any thoughts? Oh, I'm working in SQL Server 2012. Thanks!
If I understand correctly, you can use dense_rank():
select s.*
from (select shp_rev.ShpNum, shp_rev.RevTime,
dense_rank() over (partition by revdate, valafter, shipnum order by revtime desc) as seqnum
from shp_rev
where shp_rev.RevDate = '2015-10-01' and
shp_rev.ValAfter = 'O' and
shp_rev.ShpNum = 732809
) s
where seqnum = 1;
This assumes that the time stamps are all exactly the same.

Assistance with SQL Query (aggregating)

I have a requirement to create a Sales report and I have a sql query:
SELECT --top 1
t.branch_no as TBranchNo,
t.workstation_no as TWorkstation,
t.tender_ref_no as TSaleRefNo,
t.tender_line_no as TLineNo,
t.tender_code as TCode,
T.contribution as TContribution,
l.sale_line_no as SaleLineNo
FROM TENDER_LINES t
LEFT JOIN SALES_TX_LINES l
on t.branch_no = l.branch_no and t.workstation_no = l.workstation_no and t.tender_ref_no = l.sale_tx_no
where l.sale_tx_no = 2000293 OR l.sale_tx_no = 1005246 --OR sale_tx_no = 1005261
order by t.tender_ref_no asc,
l.sale_line_no desc
The results of the query look like the following:
The results I am trying to achieve is:
With only 1 line for transaction 2 either SaleLineNo 1 or 2, while still have=ing both lines for transaction 1 because the TCode is different.
Thanks
I am using SSQL2012.
Not exactly sure on what data you have, but you might want to try
GROUP BY TlineNo, TCode ...
But you have to keep a look on not to group by something that would result in duplicate contribution values.
You can use the ROW_NUMBER function that allows to partition the rows in groups, and number the lines inside each group starting by one. If you choose the right columns to define the partition, and keep only the rows with "row_number = 1`, you have solved the first part of your problem, i.e. discarding the lines that don't have to appear in the report. (See the sample sin the linked documentation, they're quite clear).
Once you have solved this problem, you simply have to repeat what you're doing, but on the result of this data, instead of the original data. You can use a view, a CTE, or a subselect to achieve your result, i.e.
With view:
CREATE VIEW FilteredData AS -- here the rank function query, then selct from the view
SELECT --here your current query --
FROM FilteredData
With CTE
WITH -- here the rank function query
SELECT -- your current querym, from the CTE
With subselect
SELECT -- your current query
FROM (SELECT FROM -- here the rank function query -- )
Appreciate your assistance with my query. After playing around, I have found a solution that works just as I want. It is as below: I did a Group by as hinted by #Yogesh86 on a few fields.
SELECT
MAX(t.branch_no) as TBranchNo,
Max(t.workstation_no) as TWorkstation,
t.tender_ref_no as TSaleRefNo,
Max(t.tender_line_no) as TLineNo,
t.tender_code as TCode,
MAx(T.contribution) as TContribution,
MAX(l.sale_line_no) as SaleLineNo
FROM TENDER_LINES t
LEFT JOIN SALES_TX_LINES l
on t.branch_no = l.branch_no and t.workstation_no = l.workstation_no and t.tender_ref_no = l.sale_tx_no
where l.sale_tx_no = 2000293 OR l.sale_tx_no = 1005246 --OR sale_tx_no = 1005261
GROUP BY
t.tender_ref_no,
t.tender_line_no,
t.tender_code