SQL Server Multiple Counts in the same Query - sql-server

I'm sure there is an easy way to do this but I've been struggling with this one...
Suppose I have an order table like so:
OrderId OrderStatus DriverId TripId
------- ----------- ------ ----
1 Available 5 2
2 Available 5 2
3 Available 5 2
4 Delivered 5 2
5 Delivered 5 3
6 Delivered 6 2
I want to group by each Driver and Trip with an extra column displaying the count of the OrderStatus when it is equal to 'Available'. So, for example
TotalOrderCountInTrip DriverId TripId AvailableOrdersCount
--------------------- -------- ------ --------------------
4 5 2 3
1 6 2 0
I've gotten this far but I can't figure out how to add the AvailableOrdersCount column:
select count(*) TotalOrderCountInTrip, dos.DriverId, dos.TripId
from DriverOrderSet dos (nolock)
group by
dos.DriverId,
dos.TripId

Add as a column:
sum(case when OrderStatus = 'Available' then 1 else 0 end)

Related

SQL Server : Join from multiple table references

Forgive me for adding yet another JOIN question, but I've been stumped all day and haven't been able to find a good answer for this.
I'm trying to join 4 tables, such that they look like below:
QuarterID ReviewID SaleID PotentialID
1 1 1 1
1 2 2 null
1 3 null 2
1 4 null null
The relevant info from the tables is below
Sale:
QuarterID
ReviewID
IsArchived
Potential:
QuarterID
ReviewID
IsArchived
Quarter:
ID
Review:
ID
We can have multiple Sales and Potentials associated with one Quarter-Review pairing, but only one Sale and one Potential will have IsArchived = 0 for the given Quarter-Review pairing.
SELECT
quarter.id AS QID,
review.id AS RID,
Sales.id AS SID,
Potentials.id AS PID
FROM
dbo.quarter
JOIN
(SELECT *
FROM dbo.sale
WHERE isarchived = 0) AS Sales ON Sales.quarterid = quarter.id
JOIN
(SELECT *
FROM dbo.potential
WHERE isarchived = 0) AS Potentials ON Potentials.quarterid = quarter.id
JOIN
dbo.review ON dbo.review.id = Sales.reviewid
AND dbo.review.id = Potentials.reviewid
ORDER BY
quarter.id, rid
Using the above (there are some unnecessary columns, I know), I've managed to get the joins so that they get the 1st condition (where its all the Sales and Potentials that are in the same Quarter and Review combination, but I also want to see if there is a Quarter/Review combo with only a Sale and no Potential, if there is a Q/R combo with only a Potential and no Sale, and just every Quarter and Review combo, since there are only a few Q/R combos that have both a Sale and Potential, with almost all of the Q/R combos only having a Sale or Potential.
I guess overall the difficulty comes from needing to get the join from two intermediate tables. I can join Quarter, Sale, and Review easily, but having the Potential table joining on the same fields (ReviewID, QuarterID) as Sale is making me only get the AND, and I can't figure out an OR. I've been throwing around ORs for hours trying to get the right sequence without any luck. Help?
--Edit to include sample data--
Quarter
ID
1
2
Review
ID (Other fields, not relevant to join)
1
2
3
4
5
Sale
ID ReviewID QuarterID isArchived (Other fields, not relevant)
1 1 1 0
2 2 1 1
3 2 1 0
4 1 2 0
5 5 1 0
6 5 2 0
Potential
ID ReviewID QuarterID isArchived (Other fields, not relevant)
1 1 1 0
2 3 1 0
3 4 2 1
4 4 2 0
5 5 2 0
Joining the above sample data, I would expect the output to look like:
QuarterID ReviewID SaleID PotentialID
1 1 1 1
1 2 3 null
1 3 null 2
1 4 null null
1 5 5 null
2 1 4 null
2 2 null null
2 3 null null
2 4 null 4
2 5 6 5
But the problem I am having is I am only returning the rows like the first and last row, where there is both a Sale and Potential for a given Quarter/Review combo, and not the ones where one or many may be null.
Not sure if I understood your question correctly (some sample data will help) but I think you mean that you need all the combinations of Quarter and Review and then any related Sale and Potential data for each combination of Quarter and Review. If that is what you need, then try the below query:
SELECT [Quarter].ID AS QID, Review.ID AS RID, Sales.ID AS SID, Potentials.ID AS PID FROM [Quarter]
CROSS JOIN [Review]
LEFT JOIN (SELECT * FROM Sale WHERE IsArchived = 0) Sales ON [Quarter].ID = Sales.QuarterID AND [Review].ID = Sales.ReviewID
LEFT JOIN (SELECT * FROM Potential WHERE IsArchived = 0) Potentials ON [Quarter].ID = Potentials.QuarterID AND [Review].ID = Potentials.ReviewID

SQL Stored Procedures : Count, Join and group by but it is shown 'NULL'

I got stuck something about stored procedures I write a stored that i need to shot three columns of products count like this
SELECT
Count([TPDTN].[ProductName]) as 'Product Count',
[TPDTN].[CategoryID]
FROM
[TPDTN]
LEFT JOIN
[TPDCN] ON [TPDTN].[CategoryID] = [TPDCN].[libDocumentID]
GROUP BY
[TPDTN].[CategoryID], [TPDCN].[libDocumentID]
It shows results like this:
Product Count CategoryID
---------------------------
2 1
9 2
2 3
2 4
1 5
But I don't know how make it show
Product Count CategoryID libDocumentID
-----------------------------------------------
2 1 123456789
9 2 123456789
2 3 123456789
2 4 123456789
1 5 123456789
Producer ID (LibdocumentID) is from other table but when I SELECT [TPDCN].[libDocumentID] the value is NULL
Product Count CategoryID libDocumentID
------------------------------------------------
2 1 NULL
9 2 NULL
2 3 NULL
2 4 NULL
1 5 NULL
How can I solve it? Thank you
Just add it to the select, and if you don't need the NULL you need an INNER JOIN:
SELECT Count([TPDTN].[ProductName]) as 'Product Count',[TPDTN].[CategoryID], [TPDCN].[libDocumentID]
FROM [TPDTN]
inner join [TPDCN]
ON [TPDTN].[CategoryID] = [TPDCN].[libDocumentID]
GROUP BY [TPDTN].[CategoryID],[TPDCN].[libDocumentID]

Transact SQL - which Join to Use

I have two simple SELECT statements:
The first shows a list of Features.
SELECT * FROM Features
id name
-- ----
1 24 Hour Access
2 24 hour CCTV monitoring
3 Airport location
4 Break-Out Areas
5 Business Lounge
6 Business park location
snip..
and the second statement shows a list of feature information that has changed
SELECT
*
FROM
#SmartFeaturesToUpdate new_features
ORDER BY
new_features.centre_translation_id,
new_features.feature_id,
new_features.feature_selected
feature_id centre_translation_id feature_selected
---------- --------------------- ----------------
1 1 1
2 1 1
5 1 1
10 1 1
11 1 1
snip..
What I want to see is all of the features by centre translation.
Combining the tables gives me:
SELECT
*
FROM
#SmartFeaturesToUpdate new_features
LEFT JOIN Feature feature ON feature.id = new_features.feature_id
ORDER BY
new_features.centre_translation_id,
new_features.feature_id,
new_features.feature_selected
feature_id centre_translation_id feature_selected id name
---------- --------------------- ---------------- -- ----
1 1 1 1 24 Hour Access
2 1 1 2 24 hour CCTV monitoring
5 1 1 5 Business Lounge
10 1 1 10 Double Glazing
11 1 1 11 Elevator
snip..
The result above is missing feature id's 3 and 4, because they are not in the second list.
but the result I need is:
feature_id centre_translation_id feature_selected id name
---------- --------------------- ---------------- -- ----
1 1 1 1 24 Hour Access
2 1 1 2 24 hour CCTV monitoring
3 1 1 3 Airport Location
4 1 1 4 Break-Out Area
5 1 1 5 Business Lounge
snip..
How should I modify the third SELECT statement to acheive this and combine the results from both the features and feature information list?
As the comments alluded, I needed another table which linked Features to centre_translation_ids
First get all of the feature / centre_translation varients
SELECT
[centre_translation_id] = centre_translation.id,
feature.id,
feature.name
INTO #AllTheFeatures
FROM
CentreTranslation centre_translation
CROSS JOIN Feature feature
ORDER BY
centre_translation.id,
feature.id
Now we can simply perform the LEFT JOIN
SELECT
all_features.centre_translation_id,
all_features.id,
all_features.name,
smart_features.feature_selected
FROM
#AllTheFeatures all_features
LEFT JOIN #SmartFeaturesToUpdate smart_features ON smart_features.centre_translation_id = all_features.centre_translation_id AND
smart_features.feature_id = all_features.id
ORDER BY
all_features.centre_translation_id,
all_features.id
This gives the results:
centre_translation_id id name feature_selected
--------------------- -- ---- ----------------
1 1 24 Hour Access 1
1 2 24 hour CCTV monitoring 1
1 3 Airport location NULL
1 4 Break-Out Areas NULL
1 5 Business Lounge 1
Why don't you just put it in one query?
SELECT
centre_translation.id AS centre_translation_id,
feature.id,
feature.name,
smart_features.feature_selected
FROM
CentreTranslation centre_translation
CROSS JOIN Feature feature
LEFT JOIN #SmartFeaturesToUpdate smart_features
ON smart_features.centre_translation_id = all_features.centre_translation_id
AND smart_features.feature_id = all_features.id
ORDER BY
centre_translation.centre_translation_id,
feature.id

Computing a field to identify chronological order of datapoints that share the same ID

I using Microsoft SQL Server 2008 to try and identify the chronological order of data points in order to create a filter field that will allow me to create a query that only includes the first and last record for each ID number, where multiple rows represent different data points from the same ID
Here is an example of my current data and desired data to give a better idea of what I mean:
Current Data
ID Indicator Date
1 1 1988-02-11
1 1 1989-03-9
1 1 1993-04-3
1 1 2001-05-4
2 1 2000-01-01
2 1 2001-02-03
2 1 2002-04-22
3 1 1990-02-01
3 1 1998-02-01
3 1 1999-03-02
3 1 2000-04-02
4 0 NA
Desired Data
ID Indicator Date Order_Indicator
1 1 1988-02-11 1
1 1 1989-03-9 2
1 1 1993-04-3 3
1 1 2001-05-4 4
2 1 2000-01-01 1
2 1 2001-02-03 2
2 1 2002-04-22 3
3 1 1990-02-01 1
3 1 1998-02-01 2
3 1 1999-03-02 3
3 1 2000-04-02 4
4 0 NULL NULL
The field I want to create is the "Order_Indicator" field in the "Desired Data" table and with the only relevant records are records with Indicator = 1. With this information I would create a query where I only select the rows where Order_Indicator = 1 and Order_Indicator = MAX(Order_Indicator) for each "row group" that share the same ID. Does anyone have any idea about how I might go about this? I know I could do this very easily in Excel but I need to do it on SQL server in order for it to be reproducible with my colleagues.
Thank you so much in advance!
You can do this with the ranking functions:
select c.*,
(case when indicator = 1
then row_number() over (partition by id, indicator order by [date])
end) as OrderIndicator
from current c
This assigns a sequential number based on the date and indicator. The case statement takes care of the indicator = 0 case.
By the way, this assumes that "date" is being stored as a date.
Use below query :
select YourTable.ID,
YourTable.indicator,
case when date<>'NA' then date end as date,
case when indicator = 1 then row_number() over (partition by id, indicator order by ID) end as Order_Indicator
from YourTable

How to assign an alternating row number based on a table primary key?

I have a table with data named Product
ProductID ProductName
1 ABC
2 PQR
3 XYZ
4 HJK
5 LKJ
6 MNB
... ....
with many more product in it. What I want is result like this on Select query:
RowNo ProductID ProductName
1 1 ABC
1 2 PQR
2 3 XYZ
2 4 HJK
1 5 LKJ
1 6 MNB
2 7 klj
2 8 hjg
then 1,1, 2,2 1,1 for the number of records in the table. Is it possible, and if so how can I do that?
This works for your sample data which assumes ProductID is contiguous:
SELECT
CASE WHEN ProductID % 4 = 0 OR (ProductID+1) % 4 = 0 THEN 2 ELSE 1 END,
ProductID,
ProductName
FROM
Product
Now, guessing that you mean in resultset which may have gaps in ProductID
SELECT
CASE WHEN ContiguousProductID % 4 = 0 OR (ContiguousProductID+1) % 4 = 0 THEN 2 ELSE 1 END,
--ContiguousProductID,
--CASE WHEN ProductID % 4 = 0 OR (ProductID+1) % 4 = 0 THEN 2 ELSE 1 END,
ProductID,
ProductName
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY ProductID) AS ContiguousProductID,
ProductName, ProductID
FROM
dbo.Product
) P2

Resources