My query looks like this. Suppose it was run well.im confused the last part of the Where clause.Can i write that from two different table?..how can i write it, cause i want to display those staff who a Active from that date range.
select d.Division,a.FirstName,
(select count(h.id) from Department h
inner join institution i on d.institution_id = i_Id
----
----
where i.institution_id =d.Id and h. date between #startDate and #endDate) as test
from Division d, inmate a
where d.Active = 1 and a.Active = 1
edited
i have edit my query and the final looks like this..
select d.DivisionName,a.FirstName, (select count(h.id) from InHistory h inner join Institution i on h.Institution_id = i.Id inner join InType it on h.InType_id = it.Id inner join mate a on h.mate_id = a.Id where i.InstitutionRegion_id = d.Id and it.InTypeName like '%Staff%' and h.AdmissionDate between '18/02/2013' and '18/02/2013') as Admission from Division d, mate a where d.Active= 1 and a.Active =1
Yes, you can give comparison between any number of tables in where clause provided you are giving valid conditions inside your where clause. I think you should refer SQL JOINS
You can add as many as you want clauses inside the WHERE from your SQL query..
see an example
SELECT *
FROM employee inner join department on
employee.DepartmentID = department.DepartmentID;
WHERE
employee.active = TRUE AND
department.group = 3
http://en.wikipedia.org/wiki/Join_(SQL)#Inner_join
Related
I have four tables, three of which are pretty static: haul_types, dumpster_type_team (the dumpster_type_team has the many-to-many relationship between dumpster_types and teams), and users. The fourth table, hauls, has transactional data.
haul_types:
id
name
dumpster_type_team:
id
dumpster_type_id
team_id
users:
id
first_name
last_name
is_driver
team_id
hauls:
haul_type_id
haul_status_id
set_dumpster_type_id
completed_driver_id
team_id
I would like a query that has a combination of dumpster_types, haul_types, and drivers (users) and a count of the hauls they were involved in. In some cases, there should be a count of zero because some drivers haven't completed hauls for every haul_type / dumpster type combination.
Here's the query I have so far that seems to be behaving as if it is an inner join because the records are getting filtered to only show where there are matches:
SELECT
c.haul_type_id,
c.dumpster_type_id,
c.driver_id,
count(h.id) AS haul_count
FROM
hauls h
RIGHT JOIN ( SELECT DISTINCT
ht.id AS haul_type_id,
dtt.dumpster_type_id AS dumpster_type_id,
dtt.team_id AS team_id,
u.id AS driver_id
FROM
haul_types ht
CROSS JOIN dumpster_type_team dtt
CROSS JOIN users u
WHERE
u.team_id = dtt.team_id
AND u.is_driver = TRUE) c ON c.haul_type_id = h.haul_type_id
AND c.dumpster_type_id = h.set_dumpster_type_id
AND c.driver_id = h.completed_driver_id
AND c.team_id = h.team_id
WHERE
h.team_id = 9
AND h.haul_status_id = 3
AND h.completed_driver_id IS NOT NULL
GROUP BY
c.haul_type_id, c.dumpster_type_id, c.driver_id
When I run the subquery in isolation:
SELECT DISTINCT
ht.id AS haul_type_id,
dtt.dumpster_type_id AS dumpster_type_id,
dtt.team_id AS team_id,
u.id AS driver_id
FROM
haul_types ht
CROSS JOIN dumpster_type_team dtt
CROSS JOIN users u
WHERE
u.team_id = dtt.team_id
AND u.is_driver = TRUE
I get the results I want: a row for each permutation of haul_type, dumpster_type, driver_id, and team_id. However, when I run the entire query, I get filtered results despite the right join.
What I would like to have is the following:
If I have 4 haul_types: delivery, swap, live, pickup
and 2 dumpster_types: 10YD, 15YD
and 2 drivers: 1, 2
I would like a haul count for the combination of haul_type, dumpster_type, and driver. If there are no hauls matching the row, show 0:
Any help is appreciated. Thank you
The description of the question and the query seem to have little to do with each other. I don't know what a "pivot table" is supposed to be.
I would like a query that has a combination of dumpster_types, haul_types, and drivers (users) and a count of the hauls they were involved in.
This sounds like a cross join to generate the rows and then a left join/group by to calculate the results:
select d.dumpster_id, ht.haul_type_id, d.driver_id, count(h.driver_id)
from dumpster_types d cross join
haul_types ht cross join
drivers d left join
hauls h
on h.dumpster_id = d.dumpster_id and
h.haul_type_id = ht.haul_type_id and
h.driver_id = d.driver_id
group by d.dumpster_id, ht.haul_type_id, d.driver_id;
Running the query #GordonLinoff provided, exposed the issue I was facing - when applying a where clause on the top level query, the results were getting filtered to only matches. I moved the where clause to individual subqueries and now I am getting all expected results.
Not sure if this is the most efficient way to write it but it yields the correct results:
SELECT
d.dumpster_type_id,
ht.id AS haul_type_id,
u.id AS driver_id,
count(h.id) AS haul_count
FROM (
SELECT
dumpster_type_id,
team_id
FROM
dumpster_type_team
WHERE
team_id = 9) d
CROSS JOIN haul_types ht
CROSS JOIN (
SELECT
users.id
FROM
users
WHERE
users.is_driver = TRUE
AND users.team_id = 9) u
LEFT JOIN (
SELECT
id, set_dumpster_type_id, haul_type_id, completed_driver_id, team_id
FROM
hauls
WHERE
haul_status_id = 3
AND team_id = 9) h ON h.set_dumpster_type_id = d.dumpster_type_id
AND h.haul_type_id = ht.id
AND h.completed_driver_id = u.id
AND h.team_id = d.team_id
GROUP BY
d.dumpster_type_id,
ht.id,
u.id
I am using the following query to retrieve the number of events per state from 2 tables that are linked by a userID.
SELECT state,COUNT(*) AS num
FROM tableUserInfo
WHERE userID IN (SELECT userID
FROM tableEvents
WHERE conditionOne = 1
AND conditionTwo = 2)
GROUP BY state
This query works correctly. My problem is that not all states have user entries, and I need the query to return 0 for those. I was wondering if there was a method such as joining or using an in clause, that would included a set of all states, making the query return 0 for any that didn't have entries in tableEvents?
Do you have a list of states? If not then this would give a list of all the states your database knows about:
SELECT DISTINCT state FROM tableUserInfo
....and enclosing this in brackets it can be dropped in place in the query below:
SELECT s.state, IFNULL(cnt, 0) AS num
FROM list_of_states s
LEFT JOIN (
SELECT state,COUNT(*) AS cnt
FROM tableUserInfo ui
INNER JOIN tableEvents te
ON ui.userId=te.userId
WHERE conditionOne = 1
AND conditionTwo = 2
GROUP BY state
) u
ON s.state=u.state;
Although in the absence of "list_of_states" it would be more efficient to do this:
SELECT ui.state, SUM(IF(te.userId IS NULL, 0, 1)) AS cnt
FROM tableUserInfo ui
LEFT JOIN tableEvents te
ON ui.userId=te.userId
AND te.conditionOne = 1
AND te.conditionTwo = 2
GROUP BY state;
As #raymond-nijland suggested you can use Left Join to include all states.
SELECT tableUserInfo.state,COUNT(tableUserInfo.*) AS num
FROM tableUserInfo Left Join tableEvents on tableUserInfo.userID = tableEvents.userID
WHERE tableEvents.conditionOne = 1 AND tableEvents.conditionTwo = 2
GROUP BY state
I have a working knowledge of SQL Server along with the ability to perform most basic queries. However, I'm stuck and needs some help with this one. I have 6 related tables from which I need to derive a set of data.
Tables are as follows:
MTMeterReadings mr
Actual
GroupID
MeterID
CreateDate
MTMeterReadingGroups mg
MeterReadingGroupID
MeterSourceID
EquipmentID
MTMeterSources ms
MeterSourceID
Description
MTMeters m
MeterID
Description
SCEquipment eq
EquipmentID
CustomerID
ARCustomers c
CustomerID
CustomerName
My desired result set is to show the following data for each Actual record in the MTMeterReadins table where mr.CreateDate > 'mm/dd/yyy':
mr.actual | mr.CreateDate | ms.description | e.EquipmentID | c.CustomerName
So far, I've been able to create a query with everything I need except c.CustomerName, but just can't seem to take it all the way (I can be JOIN challenged at times).
Any help with this is greatly appreciated.
I apologize, but I didn't know if the query I already had would be helpful or not.
Here is what I have that yields everything I want except customer name:
SELECT
mg.EquipmentID,
CAST(mr.Actual AS decimal(12, 0)) AS Meter,
CAST(mr.CreateDate AS DATE) AS MeterDate,
ms.MeterSource, m.Description
FROM
MTMeterReadings AS mr
INNER JOIN
MTMeterReadingGroups AS mg ON mr.MeterReadingGroupID = mg.MeterReadingGroupID
INNER JOIN
MTMeterSources AS ms ON mg.MeterSourceID = ms.MeterSourceID
INNER JOIN
MTMeters AS m ON mr.MeterID = m.MeterID
WHERE
(mr.CreateDate >= '01/01/2014') AND (mr.CreateDate <= '02/20/2015')
ORDER BY
MeterDate DESC, mg.EquipmentID, m.Description
However, every attempt that I have made to add CustomerName yields a multiple of the records that I have in the mr table. I can't tell exactly what my error is, but I'm assuming it is an incorrect join. Maybe simple for someone with a bigger SQL brain than me, but this is far from being inside my core knowledge base as I learned SQL from a SAMS "Teach Yourself SQL in 10 Minutes" book.
You are missing additional 2 joins:
SELECT mg.EquipmentID, CAST(mr.Actual AS decimal(12, 0)) AS Meter, CAST(mr.CreateDate AS DATE) AS MeterDate, ms.MeterSource, m.Description, ar.CustomerName
FROM MTMeterReadings AS mr INNER JOIN
MTMeterReadingGroups AS mg ON mr.MeterReadingGroupID = mg.MeterReadingGroupID INNER JOIN
MTMeterSources AS ms ON mg.MeterSourceID = ms.MeterSourceID INNER JOIN
MTMeters AS m ON mr.MeterID = m.MeterID
INNER JOIN SCEquipment eq on mg.EquipmentID = eq.EquipmentID
INNER JOIN ARCustomers ar on eq.CustomerID = ar.CustomerID
WHERE (mr.CreateDate >= '01/01/2014') AND (mr.CreateDate <= '02/20/2015')
ORDER BY MeterDate DESC, mg.EquipmentID, m.Description
It should be as simple as this:
SELECT mg.EquipmentID,
CAST(mr.Actual AS DECIMAL(12, 0)) AS Meter,
CAST(mr.CreateDate AS DATE) AS MeterDate,
ms.MeterSource,
m.Description
c.CustomerName
FROM MTMeterReadings AS mr INNER JOIN
MTMeterReadingGroups AS mg ON mr.MeterReadingGroupID = mg.MeterReadingGroupID INNER JOIN
MTMeterSources AS ms ON mg.MeterSourceID = ms.MeterSourceID INNER JOIN
MTMeters AS m ON mr.MeterID = m.MeterID INNER JOIN
SCEquipment AS e ON mg.EquipmentID = e.EquipmentID INNER JOIN
ARCustomers AS c ON e.CustomerID = c.CustomerID
WHERE (mr.CreateDate BETWEEN '01/01/2014' AND '02/20/2015')
ORDER BY MeterDate DESC,
mg.EquipmentID,
m.Description
But that's assuming that there are no possible outer joins and that every relation you want has at least one record.
Also, note that if mr.CreateDate is a datetime you will miss times on 2/20/2015 after midnight.
I have 3 tables
person (id, name)
area (id, number)
history (id, person_id, area_id, type, datetime)
In this tables I store the info which person had which area at a specific time. It is like a salesman travels in an area for a while and then he gets another area. He can also have multiple areas at a time.
history type = 'I' for CheckIn or 'O' for Checkout.
Example:
id person_id area_id type datetime
1 2 5 'O' '2011-12-01'
2 2 5 'I' '2011-12-31'
A person started traveling in area 5 at 2011-12-01 and gave it back on 2011-12-31.
Now I want to have a list of all the areas all persons have right now.
person1.name, area1.number, area2.number, area6.name
person2.name, area5.number, area9.number
....
The output could be like this too (it doesn't matter):
person1.name, area1.number
person1.name, area2.number
person1.name, area6.number
person2.name, area5.number
....
How can I do that?
This question is, indeed, quite tricky. You need a list of the entries in history where, for a given user and area, there is an 'O' record with no subsequent 'I' record. Working with just the history table, that translates to:
SELECT ho.person_id, ho.area_id, ho.type, MAX(ho.datetime)
FROM History AS ho
WHERE ho.type = 'O'
AND NOT EXISTS(SELECT *
FROM History AS hi
WHERE hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
)
GROUP BY ho.person_id, ho.area_id, ho.type;
Then, since you're really only after the person's name and the area's number (though why the area number can't be the same as its ID I am not sure), you need to adapt slightly, joining with the extra two tables:
SELECT p.name, a.number
FROM History AS ho
JOIN Person AS p ON ho.person_id = p.id
JOIN Area AS a ON ho.area_id = a.id
WHERE ho.type = 'O'
AND NOT EXISTS(SELECT *
FROM History AS hi
WHERE hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
);
The NOT EXISTS clause is a correlated sub-query; that tends to be inefficient. You might be able to recast it as a LEFT OUTER JOIN with appropriate join and filter conditions:
SELECT p.name, a.number
FROM History AS ho
JOIN Person AS p ON ho.person_id = p.id
JOIN Area AS a ON ho.area_id = a.id
LEFT OUTER JOIN History AS hi
ON hi.person_id = ho.person_id
AND hi.area_id = ho.area_id
AND hi.type = 'I'
AND hi.datetime > ho.datetime
WHERE ho.type = 'O'
AND hi.person_id IS NULL;
All SQL unverified.
You're looking for results where each row may have a different number of columns? I think you may want to look into GROUP_CONCAT()
SELECT p.`id`, GROUP_CONCAT(a.`number`, ',') AS `areas` FROM `person` a LEFT JOIN `history` h ON h.`person_id` = p.`id` LEFT JOIN `area` a ON a.`id` = h.`area_id`
I haven't tested this query, but I have used group concat in similar ways before. Naturally, you will want to tailor this to fit your needs. Of course, group concat will return a string so it will require post processing to use the data.
EDIT I thikn your question has been edited since I began responding. My query does not really fit your request anymore...
Try this:
select *
from person p
inner join history h on h.person_id = p.id
left outer join history h2 on h2.person_id = p.id and h2.area_id = h.area_id and h2.type = 'O'
inner join areas on a.id = h.area_id
where h2.person_id is null and h.type = 'I'
I have three tables that looks something like this:
Table joins
|ID|JOIN_NAME|
1 persons
2 companies
Table information
|ID|JOIN_ID|
1 1
2 2
Table information_extra_persons
|ID|INFORMATION_ID|NAME|
1 1 John
Table information_extra_companies
|ID|INFORMATION_ID|NAME|
1 2 IBM
How can i join together these tables in one SQL? I've tried something like:
SELECT * FROM `information`
INNER JOIN `information_extra_(SELECT `name` FROM `joins` WHERE `id` = `join_id`)`
ON `information_extra_(SELECT `name` FROM `joins` WHERE `id` = `join_id`)`.`information_id` = `information`.`id`
but I can't get it to work. Of course this isn't my actual table setup, but it's the same principle. Does anyone know how to get all the info in just one SQL?
That's actually four tables, not three. This isn't just a nitpick - it looks as though the substance of your question is "how can I use the name of the table as part of the join criteria?" (ie. how can the information_extra_ tables be treated as a single table?)
To which the answer is: you can't. (Outside of dynamic SQL.)
In this specific case, the following should return what I think you are looking for:
select j.join_name joined_entity,
case when j.join_name = 'persons' then p.name
else c.name
end joined_entity_name
from information i
inner join joins j on i.join_id = j.id
left join information_extra_persons p on i.id = p.information_id
left join information_extra_companies c on i.id = c.information_id
Alternatively, a less efficient (but more general) approach might be:
select j.join_name joined_entity,
v.name joined_entity_name
from information i
inner join joins j on i.join_id = j.id
inner join (select 'persons' entity, information_id, name from information_extra_persons
union all
select 'companies' entity, information_id, name from information_extra_companies) v
on i.id = v.information_id and j.join_name = v.entity