SQL Query Assistance - sql

I'm having a complete brain fart moment so i figured i'd ask away here.
I have 3 tables that look like this
Equipment Table
EquipmentID | LocationID
-------------------------
1 | 2
2 | 2
3 | 1
4 | 2
5 | 3
6 | 3
Location Table
LocationID | LocationName
--------------------------
1 | Pizza Hut
2 | Giordanos
3 | Lou Malnati's
Service Table
LocationID | EquipmentID | Status
-----------------------------------
2 | 1 | Serviced
2 | 2 | Not Yet Serviced
2 | 4 | Not Yet Serviced
3 | 5 | Serviced
I need a way to list all locations that have had one or more equipment(s) serviced, but not all of the equipments at the location have been serviced yet.
So for the example above it would return the following results
LocationID | ServicedEquipmentID | NotServicedEquipmentIDS | LocationStatus
------------------------------------------------------------------------------
2 | 1 | 2, 4 | Partially Serviced
3 | 5 | 6 | Partially Serviced
Thanks for any help!

This query will give you the location status you desire, although not the individual equipment statuses:
SELECT [LocationId]
,[LocationId]
,CASE ( [IsServiced] + [IsNotServiced] )
WHEN 0 THEN 'Not Serviced'
WHEN 1 THEN 'Partially Serviced'
WHEN 2 THEN 'Serviced'
END [LocationStatus]
FROM ( SELECT [l].[LocationId]
,[e].[LocationId]
,CASE [s].[Status]
WHEN 'Serviced' THEN 1
ELSE 0
END [IsServiced]
,CASE [s].[Status]
WHEN 'Not Yet Serviced' THEN 1
ELSE 0
END [IsNotServiced]
FROM [Location] l
INNER JOIN [Equipment] e ON [l].[LocationId] = [e].[LocationId]
INNER JOIN [Service] s ON [l].[LocationId] = [s].[LocationId]
AND [e].[EquipmentId] = [s].[EquipmentId]
) x
To add a comma-seperated list of equipmentIds that have been/not been serviced to the result set, you will need a CONCAT function of some sort. Either a UDF, CLR, or a recursive CTE (I don't have time to write that right now -- here's a link).

Related

MS SQL Query to get all entries comming multiple times in table where some column value doesnt have entries

I just tried to formulate title as best as possible. So my case is as follow.
i have a table
venue_id | style_id | is_main
1 | 1 | 1
1 | 2 | 0
1 | 3 | 0
2 | 5 | 0
2 | 8 | 0
2 | 9 | 0
3 | 3 | 1
4 | 4 | 1
4 | 6 | 0
5 | 7 | 0
5 | 8 | 0
5 | 9 | 0
So i need to get only those venue ID, witch coming more then once and where is no is_main true entry.
So result should be contain venue_id's: 2 and 5
I would grateful for any suggestion how such query may looks like.
Thanks in Advance.
UPD: in my case with is_amin BIT value answer would be:
select venue_id
from table
group by venue_id
having cast(max(cast(is_main as INT)) AS BIT) = 0 and
count(*) >= 2;
You seem to want:
select venue_id
from t
group by venue_id
having max(is_main) = 0 and
count(*) >= 2;
You can use this one:
SELECT DISTINCT v.venue_id FROM venue v
LEFT OUTER JOIN (SELECT DISTINCT venue_id FROM venue WHERE is_main=1) m
ON v.venue_id = m.venue_id
WHERE m.venue_id IS NULL
If you have many thousands of rows, it would be better to create a secondary table or a materialized view to be used in place of the nested SELECT.

select records where condition is true in one record

I need to select cid, project, and owner from rows in the table below where one or more rows for a cid/project combination has an owner of 1.
cid | project | phase | task | owner
-----------------------------------
1 | 1 | 1 | 1 | 1
1 | 1 | 1 | 2 | 2
1 | 1 | 1 | 3 | 2
2 | 1 | 1 | 1 | 1
2 | 1 | 1 | 2 | 1
3 | 1 | 1 | 3 | 2
My output table should look like the this:
cid | project | phase | task | owner
-----------------------------------
1 | 1 | 1 | 1 | 1
1 | 1 | 1 | 2 | 2
1 | 1 | 1 | 3 | 2
2 | 1 | 1 | 1 | 1
2 | 1 | 1 | 2 | 1
The below query is what I came up with. It does seem to test okay, but my confidence is low. Is the query an effective way to solve the problem?
select task1.cid, task1.project, task1.owner
from
(select cid, project, owner from table) task1
right join
(select distinct cid, project, owner from table where owner = 1) task2
on task1.cid = task2.cid and task1.project = task2.project
(I did not remove the phase and task columns from the sample output so that it would be easier to compare.)
You can simply use a IN clause
select cid, project, owner
from table
where cid in (select distinct id from table where owner = 1)
or a inner join with a subquery
select a.cid, a.project, a.owner
from table a
INNER JOIN ( select distinct cid , project
from table where owner = 1
) t on t.cid = a.cid and t.project = a.project

Microsoft Access query to duplicate ROW_NUMBER

Obviously there are a bunch of questions about ROW_NUMBER in MS Access and the usually response is that it does not exist but instead to use a COUNT(*) to create something similar. Unfortunately, doing so does not give me the results that I need.
My data looks like:
RID | QID
---------
1 | 1
1 | 2
1 | 3
1 | 3
2 | 1
2 | 2
2 | 2
What I am trying to get at is a unique count over RID and QID so that my query output looks like
RID | QID | SeqID
------------------
1 | 1 | 1
1 | 2 | 1
1 | 3 | 1
1 | 3 | 2
2 | 1 | 1
2 | 2 | 1
2 | 2 | 2
Using the COUNT(*) I get:
RID | QID | SeqID
------------------
1 | 1 | 1
1 | 2 | 2
1 | 3 | 3
1 | 3 | 3
2 | 1 | 1
2 | 2 | 2
2 | 2 | 2
My current query is:
SELECT
d.RID
,d.QID
,(SELECT
COUNT(*)
FROM
Data as d2
WHERE
d2.RID = d.RID
AND d2.QID < d.QID) + 1 AS SeqID
FROM
Data as d
ORDER BY
d.RID
,d.QID
Any help would be greatly appreciated.
As Matt's comment implied, the only way to make this work is if you have some column in your table that can uniquely identify each row.
Based on what you have posted, you don't seem to have that. If that's the case, consider adding a new auto increment numeric column that can serve that purpose. Let's pretend that you call that new column id.
With that in place, the following query will work:
select t.rid, t.qid,
(select count(*)
from data t2
where t2.rid = t.rid
and t2.qid = t.qid
and t2.id <= t.id) as SeqID
from data t
order by t.rid, t.qid
SQLFiddle Demo

Query returned with an extra column in sql -ms access

So I am wondering. I fell into an interesting suggestion from another developer. So i basically have two tables I join in a query and I want the resulting table from the query to have an extra column that comes from the table on from the joint.
Example:
#table A: contains rating of players, changes randomly at any date depending
#on drop of form from the players
PID| Rating | DateChange |
1 | 2 | 10-May-2014 |
1 | 4 | 20-May-2015 |
1 | 20 | 1-June-2015 |
2 | 4 | 1-April-2014|
3 | 4 | 5-April-2014|
2 | 3 | 3-May-2015 |
#Table B: contains match sheets. Every player has a different match sheet
#and plays different dates.
MsID | PID | MatchDate | Win |
1 | 2 | 10-May-2014 | No |
2 | 1 | 15-May-2015 | Yes |
3 | 3 | 10-Apr-2014 | No |
4 | 1 | 21-Apr-2015 | Yes |
5 | 1 | 3-June-2015 | Yes |
6 | 2 | 5-May-2015 | No |
#I am trying to achieve this by running the ms-access query: i want to get
#every players rating at the time the match was played not his current
#rating.
MsID | PID | MatchDate | Rating |
1 | 2 | 10-May-2014 | 4 |
2 | 1 | 15-May-2015 | 2 |
3 | 3 | 10-Apr-2014 | 4 |
4 | 1 | 21-Apr-2015 | 4 |
5 | 1 | 3-June-2015 | 20 |
6 | 2 | 5-May-2015 | 3 |
This is what I have tried below:
Select MsID, PID, MatchDate, A-table.rating as Rating from B-table
left Join A-table
on B-table.PID = A-table.PID
where B-table.MatchDate > A-table.Datechange;
any help is appreciated. The solution can be in Vba as long as it returns something like a view/table I can manipulate using other queries or report.
Think of this in terms of sets of data... you need a set that lists the MAX dateChange for each player's and match date.
Soo...
SELECT MAX(A.DateChange) MDC, A.PID, B.Matchdate
FROM B-table B
INNER Join A-table A
on B.PID = A.PID
and A.DateChange <= B.MatchDate
GROUP BY A.PID, B.Matchdate
Now we take this and join it back to what you've done to limit the results in table A and B to ONLY those with that date player and matchDate (my inline table C)
SELECT B.MsID, B.PID, B.MatchDate, A.rating as Rating
FROM [B-table] B
INNER JOIN [A-table] A
on B.PID = A.PID
INNER JOIN (
SELECT MAX(Y.DateChange) MDC, Y.PID, Z.Matchdate
FROM [B-table] Z
INNER Join [A-table] Y
on Z.PID = Y.PID
and Y.DateChange <= Z.MatchDate
GROUP BY Y.PID, Z.Matchdate) C
on C.mdc = A.DateChange
and A.PID = C.PId
and B.MatchDate = C.Matchdate
I didn't create a sample for this using your data so it's untested but I believe the logic is sound...
Now Tested! SQL Fiddle using SQL server though...
My results don't match yours exactly. I think you're expected results are wrong though for MSID 4 given rules defined.

How to GROUP BY into separate columns

I have 3 tables:
The first one contains information about persons. The relevant column is the personID.
The second contains exercises a person can do. There are for example 3 exercises with an exID.
The third contains the points a person (personID) reached in an exercise (exID). So each row here stands for an examination a person has taken. But not everyone need to have taken every exam.
What I would like to have is a result with the columns personID, exam_one, exam_two, exam_three, ...(ongoing, depending on how many exams there are). And each row of the result should contain the personID and the points from the respective exam.
For exams not taken there should be NULL or something.
Example for table persons:
personID | Name | ...
-------------------
1 | Max |
2 | Peter |
Example for exercises table:
exID | exName | maxPoints | ...
-------------------------------
1 | exam1 | 20
2 | exam2 | 25
3 | exam3 | 20
Example for points table:
personID (fkey) | exID (fkey) | points
----------------------------------------
1 | 1 | 12.5
1 | 3 | 10
2 | 1 | 5
2 | 2 | 8.5
2 | 3 | 10
Wished result:
personId | exam1 | exam2 | exam3
------------------------------------
1 | 12.5 | NULL | 10
2 | 5 | 8.5 | 10
Is there a way to do this? I use PostgreSQL
You can use something like the following:
select p.personId,
sum(case when e.exname = 'exam1' then t.points end) Exam1,
sum(case when e.exname = 'exam2' then t.points end) Exam2,
sum(case when e.exname = 'exam3' then t.points end) Exam3
from persons p
left join points t
on p.personID = t.personID
left join exercises e
on t.exid = e.exid
group by p.personid
See SQL Fiddle with Demo