Skip an entry WHERE ROW_NUMBER() = X And corresponding entry = 'Y' - sql-server

I have a table with the ROW_NUMBER() partitioned over the User:
Row|Activity|User
-----------------
1 |A |Jeff
2 |A |Jeff
3 |A |Jeff
1 |A |Bob
2 |B |Bob
3 |C |Bob
1 |A |Sam
2 |B |Sam
3 |A |Sam
4 |D |Sam
I would like to skip, during the row count, the entry 3 for Jeff and Sam because if a User's 3rd Activity is A, I should skip it. I call the to-be-skipped rows 'restricted rows'. Basically, I want this table as a result (Without the comments obviously):
Row|Activity|User
-----------------
1 |A |Jeff
2 |A |Jeff --3rd activity is A so it gets skipped
1 |A |Bob
2 |B |Bob
3 |C |Bob --3rd activity isn't A so it doesn't get skipped
1 |A |Sam
2 |B |Sam --3rd activity is A so it gets skipped
3 |D |Sam
My query:
SELECT ROW_NUMBER() OVER(PARTITION BY User) AS Row, Activity, User FROM Table1
WHERE [Filters]
AND User IN(SELECT User IN Table1
WHERE [Filters] --Same filters as above
GROUP BY User HAVING COUNT(User) > 1) --Let's call this the 'Minimum 1 Activity Filter'
I am going to be perfectly honest, right now, I don't know if the Minimum 1 Activity Filter will cause problems later, aka if Row 2 will also have restrictions. Because of that, I prefer treading on the safe side and imagine that I will have to check the Minimum 1 Activity Filter once all the restricted rows have been taken care of.

if a User's 3rd Activity is A, I should skip it
Consider:
select
row_number() over(partition by user order by id) rn,
activity,
user
from (
select
t.*,
row_number() over(partiton by user order id) rn
from mytable t
) t
where not (rn = 3 and activity = 'A')
Note that, for this to work, you do need a column that can be used to sort the records - I assumed column id.

Related

select top 1 from different sub queries to implement basic item routing function

I am trying to implement a very simple routing system, which allows an item to go from one step to another, based on the routing information from related tables. My ASP.NET method should get the next step based on a database result, in order to avoid any stupid hardcoded values.
There is a table that contains the active steps (all steps "to do", or not to do, bit: 1 or 0) and another one with the completed steps. Based on this information I believe I should be able to do a select top 1 (the next step) from the table containing all the active steps, where the stepID is not in the list of already completed stepIDs.
I have tried this on paper and it made sense, I have also tried to work my way up from the detailed queries to the big query, which should return the next step (top 1). The bottom level queries work, however, I am having problems with my big query that should return the top 1 item (next step). I always get the following error:
"Msg 156, Level 15, State 1. Incorrect syntax near the keyword
'WHERE'. Msg 156, Level 15, State 1. Incorrect syntax near the keyword
'NOT'. (Line 4)"
Table overview as follows.
Table Routes containing all steps to be done (or not -> 0)
itemID |routeID |stepID |stepScheduled |
-------|--------|-------|--------------|
1 |1 |10 |1 |
2 |1 |20 |1 |
3 |1 |30 |1 |
4 |1 |40 |1 |
5 |1 |50 |1 |
6 |1 |60 |1 |
7 |1 |70 |1 |
8 |1 |80 |1 |
9 |1 |90 |1 |
10 |1 |100 |1 |
----------------------------------------
Table Steps_Completed containing the steps that are completed (could be empty if this item has not completed any steps yet).
completionID |sampleID |stepID |userName |completionDT |stationID |
-------------|---------|-------|---------|--------------------|--------------|
1 |1 |10 |Me |2017-12-28 10:04:41 |workstation 1 |
------------------------------------------------------------------------------
Query I am currently trying that is returning the error message mentioned above:
SELECT TOP 1 stepID FROM
(SELECT [stepID] **Routes** WHERE [routeID] = 1 AND [stepScheduled] = 1)
WHERE stepID NOT IN (SELECT stepID FROM **Steps_Completed** WHERE sampleID =
1);
The sub queries in () work when executed separately and return the expected values:
(SELECT [stepID] from Routes WHERE [routeID] = 1 AND [stepScheduled] = 1)
Returns all rows as seen in the first table (all "to do")
(SELECT stepID FROM Steps_Completed WHERE sampleID =
1)
Returns all rows that have been completed or an empty result if nothing has been recorded yet.
The idea was to do a basic "substraction" of the "Route" list, "minus" the completed steps and then selecting the top 1 item of the remaining list. Since the list of stepIDs can be ordered by ASC, then the top 1 item should be my result.
The problem appears to be with the "WHERE stepID NOT IN" part.
Here is the immediate fix to your current query:
SELECT TOP 1 [stepID]
FROM Routes
WHERE
[routeID] = 1 AND
[stepScheduled] = 1 AND
[stepID] NOT IN (SELECT stepID FROM Steps_Completed WHERE sampleID = 1)
ORDER BY
[stepID];
Another way to phrase this would be using a left join:
SELECT TOP 1 r.stepID
FROM Routes r
LEFT JOIN Steps_Completed s
ON r.routeID = s.sampleID AND
r.stepID = s.stepID
WHERE
r.routeID = 1 AND
r.stepScheduled = 1 AND
s.sampleID IS NULL
ORDER BY
r.stepID;
One key point to note here is that we generally must use ORDER BY along with TOP. Otherwise, the "top" is not well defined, as SQL tables have no internal order. Also, I don't think you need to necessarily use a subquery here, so I have removed it.
Using Alias:
SELECT TOP 1 stepID FROM
(SELECT [stepID] from Routes WHERE [routeID] = 1 AND [stepScheduled] = 1) as a
WHERE stepID NOT IN (SELECT stepID FROM Steps_Completed WHERE sampleID =
1);
SELECT stepID
FROM Routes
WHERE stepID = (SELECT MIN(stepId)
FROM Routes r
LEFT JOIN Steps_Completed sc
ON r.stepID = sc.stepID
WHERE [routeID] = 1
AND [stepScheduled] = 1
AND sc.stepID is null)

Using MAX in WHERE Clause with < -Operator

I want to select the entries in a table when the registration adress is equal to one (of more than one) delivery adresses AND this adress is the adress where the customer sent all his orders to this adress, since the adress was created.
Date 1 = Date of first order to specific adress, Date 2 = Last/Newest Order to specific adress.To make iot easier to understand... I´ve got this (Table1):
The task:
|cID ||company|Street |Code|del |Street2 |Cod2|Date 1 |Date 2 |
+------------------------------------------------------------------------+
|1 ||Ex1 |ABC Rd.1|4025|Ex1 |DEL St.1|0212|01.01.2015|06.03.2015|
|1 ||Ex1 |ABC Rd.1|4025|Ex1 |REF Wy.1|9875|26.02.2015|16.05.2015|
|1 ||Ex1 |ABC Rd.1|4025|Ex1 |ABC Rd.1|4025|13.06.2015|08.08.2015|
|2 ||Ex2 |HIO Wy.1|9999|Ex2 |DEL St.1|0212|13.03.2015|09.07.2015|
|2 ||Ex2 |HIO Wy.1|9999|Ex2 |REG St.1|6754|21.02.2015|16.05.2015|
|2 ||Ex2 |HIO Wy.1|9999|Ex2 |BLA Rd.5|0897|01.03.2015|06.12.2015|
|2 ||Ex2 |HIO Wy.1|9999|Ex2 |HIO Wy.1|9999|09.10.2015|26.11.2015|
|3 ||Ex3 |REG St.1|1114|Ex3 |DEL St.9|0212|13.01.2015|09.02.2015|
|3 ||Ex3 |REG St.1|1114|Ex3 |REG St.1|6754|21.03.2015|16.09.2015|
|3 ||Ex3 |REG St.1|1114|Ex3 |BLA Rd.5|0897|08.06.2015|06.08.2015|
|4 ||Ex4 |FAR RD.9|4567|Ex4 |DDR Wy.2|0897|01.03.2015|06.12.2015|
|4 ||Ex4 |FAR RD.9|4567|Ex4 |FAR RD.9|4567|09.10.2015|26.12.2015|
Expected Result
|cID ||company|Street |Code|del |Street |Code|Date 1 |Date 2 |
+------------------------------------------------------------------------+
|1 ||Ex1 |ABC Rd.1|4025|Ex1 |ABC Rd.1|4025|13.06.2015|08.08.2015|
respectively cID = 1
Here´s what I tried so far, but it´s not working....
SELECT cID
FROM Table1
WHERE company= del
AND Street = Street2
AND Code = Cod2
AND (SELECT MAX (Date 1) > (=! MAX(Date2) FROM Table1 Group by CID)
Edit (To make it more simple to understand):
e.g. the company with the name Ex1 (cID 1) is now located in ABC Rd.1|4025 (actual adress - the adress before is unknown) and has 3 adresses in system, where the orders of the company has been send to.
The first order on adress 1 (DEL St.1|0212) was on 01.01.2015,
the last order to this adress was on 06.03.2015.
The first order on adress 2 (REF Wy.1|9875) was on 26.02.2015
and the last order to this adress was on 16.05.2015 ...
-> I want the cID´s where registration adress (actual adress of the company) is the actual and only delivery adress.
Try using row number to get the latest date.
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER ( PARTITION BY Street, Code, company
ORDER BY Date1 DESC) as rn
FROM Table1
WHERE Street = Street2
AND Code = Cod2
AND company = del
) T
WHERE T.rn = 1
This should work:
SELECT cID
FROM Table1
WHERE Street = Street2
AND Code = Cod2
AND Date1 > (
SELECT MAX(Date2)
FROM Table1 as delivery
WHERE Table1.cID = delivery.cID
AND (delivery.Street2 <> Street OR delivery.Cod2 <> Code)
)
The subquery must itself be a correct SELECT-FROM-WHERE query, and a variable must be used to disambiguate between the outer and inner tables. The inner query selects all deliveries made to the same company but excluding the current delivery, and picks the maximal most recent date. It is then compared to the oldest date of the current delivery address.
Note that the data is not in second normal form. It may be worth, depending on the use case, splitting the table into a table with companies and a table with deliveries.
On my side, it returns 1 as expected.

Sum up delivered companies for every customer(ID)

I'm back in action ;) This time I have a pretty heavy task (I think).
Here's what I got:
|customerID ||company |compdel |Street |Code |Date 1 |Date 2 |
+-------------------------------+--------------------------------------+
|1 ||Example1 |DELExam1|ABC Rd.1|4025 |01.01.2015 |01.08.2015 |
|1 ||Example1 |DELExam1|ABC Rd.1|4025 |13.04.2015 |01.12.2015 |
|1 ||Example1 |DELExam2|DEL St.1|0212 |13.03.2015 |09.07.2015 |
|1 ||Example1 |DELExam3|REF Wy.1|9875 |26.05.2015 |16.09.2015 |
|2 ||Example2 |DELExam4|REG St.1|6754 |21.02.2015 |16.05.2015 |
|2 ||Example2 |DELExam5|HIO Wy.1|9999 |01.03.2015 |06.08.2015 |
|2 ||Example2 |DELExam5|HIO Wy.1|9999 |01.01.2015 |06.02.2015 |
I want to show for every customerID every delivered company (compdel) summed in one line with the earliest date in Date 1 and the newest Date in Date 2. To make it easier to understand, I want this result:
|customerID ||company |compdel |Street |Code |Date 1 |Date 2 |
+-------------------------------+--------------------------------------+
|1 ||Example1 |DELExam1|ABC Rd.1|4025 |01.01.2015 |01.12.2015 |
|1 ||Example1 |DELExam2|DEL St.1|0212 |13.03.2015 |09.07.2015 |
|1 ||Example1 |DELExam3|REF Wy.1|9875 |26.05.2015 |16.09.2015 |
|2 ||Example2 |DELExam4|REG St.1|6754 |21.02.2015 |16.05.2015 |
|2 ||Example2 |DELExam5|HIO Wy.1|9999 |01.01.2015 |06.08.2015 |
I tried it already with this select-Statement but it won´t work: I know, that this can only be a part of the answer....
SELECT *
FROM
(SELECT
customerID, company, compdel, Street, Code, Date 1, Date 2,
ROW_NUMBER() OVER(PARTITION BY compdel ORDER BY customerID) rn
FROM
table 1) as Y
WHERE
rn = 1
Use GROUP BY with distinct values (customerId, company etc.) and MIN and MAX for dates
SELECT CustomerId
, Company
, CompDel
, Street
, Code
, MIN(Date1) As EarliestDate1
, MAX(Date2) AS NewestDate2
FROM YourTable
GROUP BY CustomerId, Company, CompDel, Street, Code

How to get the count of each distinct value in Multiple columns and get the result in separate columns?

I need the following table to be queried to get the result given below the table.
Table:
----------------------------------
| Name | Age | slot |
|-------|--------|---------------|
|A |20 | 1 |
|B |30 | 2 |
|C |30 | 1 |
|D |20 | 1 |
|E |40 | 2 |
|F |40 | 3 |
|G |50 | 3 |
----------------------------------
Result:
-------------------------------------------
|Age |Age_Count |Slot |Slot_Count|
-------------------------------------------
|20 | 2 |1 |3 |
-------------------------------------------
|30 | 2 |2 |2 |
-------------------------------------------
|40 | 2 |3 |2 |
-------------------------------------------
|50 | 1 |
-----------------------
While searching stackoverflow i found this question for single column question and there is [this link for multiple columns] (get the count of each distinct value in "Multiple" columns) question. The answers from the second link (for the multiple coulmn's distinct count) is displayed under a single column and my requirement is i guess quite different from the answers posted there.
Thanks in advance
Your request is kind of odd. Are you sure you want that?
If so, this may help:
SET #x:=0,#y:=0,#m:=0,#n:=0;
SELECT
DISTINCT age,age_count, slot,slot_count
FROM (
SELECT
age, age_count, slot, slot_count
FROM (
SELECT
#x:=#x + 1 AS aid, age, COUNT(*) age_count
FROM
slots
GROUP BY age
) a
LEFT JOIN (
SELECT
#y:=#y + 1 AS sid, slot, COUNT(*) slot_count
FROM
slots
GROUP BY slot
) s ON a.aid = s.sid
UNION
SELECT
age, age_count, slot, slot_count
FROM (
SELECT
#m:=#m + 1 AS aid, slot, COUNT(*) slot_count
FROM
slots
GROUP BY slot
) a
LEFT JOIN (
SELECT
#n:=#n + 1 AS sid, age, COUNT(*) age_count
FROM
slots
GROUP BY age
) s ON a.aid = s.sid
) a
If you know for sure that you have more unique ages than unique slots , or opposite, you can get ride of messy union.

Reshaping data file from rows to columns in SQL-SERVER

I have a query that returns a dataset with 2 columns, as shown below:
--------------------------
|spec-number|project |
|-----------|-----------|
|649841 |A |
|649841 |B |
|649841 |D |
|84709 |E |
|84709 |B |
|84709 |C |
|84709 |K |
-------------------------
The number of projects a spec-number could be involved in could potentially be infinite.
What I would like the result to look like is:
-------------------------------------------------
|spec-number|project1|project2|project3|project4|
|-----------|--------|--------|--------|--------|
|649841 |A |B |D | |
|84709 |E |B |C |K |
-------------------------------------------------
I tried pivoting but it just gives me a cross tab of projects by spec-number.
Any help would be greatly appreciated!
If you want them as separate columns, then you can calculate the project number and use that for pivoting. The following uses the group by method for aggregation:
select spec_num,
max(case when seqnum = 1 then project end) as project1,
max(case when seqnum = 2 then project end) as project2,
max(case when seqnum = 3 then project end) as project3,
max(case when seqnum = 4 then project end) as project4
from (select t.*,
row_number() over (partition by spec_number order by project) as seqnum
from t
) t
group by spec_num;
If you need a variable number of columns, then you'll have to use dynamic SQL. This can also be phrased as a pivot query, if you prefer.

Resources