SQL Query Unique Equipment List - sql

Thanks in advance for having a look. I have no idea on how to search for this.
Picture 2 test stations, each with a rack of equipment that must be kept calibrated. The equipment is identified by stationId, eqPartno, and eqLocation. Location instead of serial number so it is unit replaceable.
From 2 tables:
station_events (eventId is auto, recUpdated is auto)
"stationEventId","stationId","stationEvent","recUpdated"
1,"1","databaseCreation",2014-05-14 07:51:25 AM
2,"55","databaseCreation",2014-05-14 07:51:25 AM
3,"1","updateCal",2014-05-14 08:11:26 AM
4,"1","updateCal",2014-05-14 08:11:59 AM
5,"1","updateCal",2014-05-14 08:48:26 AM
equipment (equipmentId is auto, recUpdated is auto, linked by equipmentId)
"equipmentId","stationEventId","eqPartNo","eqLocation","eqCalExpires","eqRecUpdated"
1,1,"eq1","loc1",2000-01-31,2014-05-14 07:53:59 AM
2,1,"eq2","loc2",2000-02-22,2014-05-14 08:05:52 AM
3,3,"eq1","loc1",2014-04-04,2014-05-14 08:13:37 AM
4,4,"eq2","loc2",2014-04-05,2014-05-14 08:14:25 AM
5,5,"eq1","loc1",2014-04-05,2014-05-14 08:47:04 AM
The query is to form a view of station 1 equipment consisting of the latest record for each of the installed units to verify cal.
select e.* from equipment e
inner join station_events se on se.stationEventId=e.stationEventId
where se.stationId='1'
group by eqPartNo,eqLocation
The results look good.
"equipmentId","stationEventId","eqPartNo","eqLocation","eqCalExpires","eqRecUpdated"
5,5,"eq1","loc1",2014-04-05,2014-05-14 08:47:04 AM
4,4,"eq2","loc2",2014-04-05,2014-05-14 08:14:25 AM
Have I just created a lucky hack, or is this correct? I like this because we have calibration history as long as the view is guaranteed to describe all the latest equipment records.
Best Regards,
Jim Shedden

This is lucky one. You may insert an aggregate such MAX into your query
select e.equipmentId,
e.stationEventId,
e.eqPartNo,
e.eqLocation,
e.eqCalExpires,
MAX(e.eqRecUpdated) from equipment e
inner join station_events se on se.stationEventId=e.stationEventId
where se.stationId='1'
group by eqPartNo,eqLocation

Related

Sql Left or Right Join One To Many Pagination

I have one main table and join other tables via left outer or right outer outer join.One row of main table have over 30 row in join query as result. And I try pagination. But the problem is I can not know how many rows will it return for one main table row result.
Example :
Main table first row result is in my query 40 rows.
Main table second row result is 120 row.
Problem(Question) UPDATE:
For pagination I need give the pagesize the count of select result. But I can not know the right count for my select result. Example I give page no 1 and pagesize 50, because of this I cant get the right result.I need give the right pagesize for my main table top 10 result. Maybe for top 10 row will the result row count 200 but my page size is 50 this is the problem.
I am using Sql 2014. I need it for my ASP.NET project but is not important.
Sample UPDATE :
it is like searching an hotel for booking. Your main table is hotel table. And the another things are (mediatable)images, (mediatable)videos, (placetable)location and maybe (commenttable)comments they are more than one rows and have one to many relationship for the hotel. For one hotel the result will like 100, 50 or 10 rows for this all info. And I am trying to paginate this hotels result. I need get always 20 or 30 or 50 hotels for performance in my project.
Sample Query UPDATE :
SELECT
*
FROM
KisiselCoach KC
JOIN WorkPlace WP
ON KC.KisiselCoachId = WP.WorkPlaceOwnerId
JOIN Album A
ON KC.KisiselCoachId = A.AlbumId
JOIN Media M
ON A.AlbumId = M.AlbumId
LEFT JOIN Rating R
ON KC.KisiselCoachId = R.OylananId
JOIN FrUser Fr
ON KC.CoachId = Fr.UserId
JOIN UserJob UJ
ON KC.KisiselCoachId = UJ.UserJobOwnerId
JOIN Job J
ON UJ.JobId = J.JobId
JOIN UserExpertise UserEx
ON KC.KisiselCoachId = UserEx.UserExpertiseOwnerId
JOIN Expertise Ex
ON UserEx.ExpertiseId = Ex.ExpertiseId
Hotel Table :
HotelId HotelName
1 Barcelona
2 Berlin
Media Table :
MediaID MediaUrl HotelId
1 www.xxx.com 1
2 www.xxx.com 1
3 www.xxx.com 1
4 www.xxx.com 1
Location Table :
LocationId Adress HotelId
1 xyz, Berlin 1
2 xyz, Nice 1
3 xyz, Sevilla 1
4 xyz, Barcelona 1
Comment Table :
CommentId Comment HotelId
1 you are cool 1
2 you are great 1
3 you are bad 1
4 hmm you are okey 1
This is only sample! I have 9999999 hotels in my database. Imagine a hotel maybe it has 100 images maybe zero. I can not know this. And I need get 20 hotels in my result(pagination). But 20 hotels means 1000 rows maybe or 100 rows.
First, your query is poorly written for readability flow / relationship of tables. I have updated and indented to try and show how/where tables related in hierarchical relativity.
You also want to paginate, lets get back to that. Are you intending to show every record as a possible item, or did you intend to show a "parent" level set of data... Ex so you have only one instance per Media, Per User, or whatever, then once that entry is selected you would show details for that one entity? if so, I would do a query of DISTINCT at the top-level, or at least grab the few columns with a count(*) of child records it has to show at the next level.
Also, mixing inner, left and right joins can be confusing. Typically a right-join means you want the records from the right-table of the join. Could this be rewritten to have all required tables to the left, and non-required being left-join TO the secondary table?
Clarification of all these relationships would definitely help along with the context you are trying to get out of the pagination. I'll check for comments, but if lengthy, I would edit your original post question with additional details vs a long comment.
Here is my SOMEWHAT clarified query rewritten to what I THINK the relationships are within your database. Notice my indentations showing where table A -> B -> C -> D for readability. All of these are (INNER) JOINs indicating they all must have a match between all respective tables. If some things are NOT always there, they would be changed to LEFT JOINs
SELECT
*
FROM
KisiselCoach KC
JOIN WorkPlace WP
ON KC.KisiselCoachId = WP.WorkPlaceOwnerId
JOIN Album A
ON KC.KisiselCoachId = A.AlbumId
JOIN Media M
ON A.AlbumId = M.AlbumId
LEFT JOIN Rating R
ON KC.KisiselCoachId = R.OylananId
JOIN FrUser Fr
ON KC.CoachId = Fr.UserId
JOIN UserJob UJ
ON KC.KisiselCoachId = UJ.UserJobOwnerId
JOIN Job J
ON UJ.JobId = J.JobId
JOIN UserExpertise UserEx
ON KC.KisiselCoachId = UserEx.UserExpertiseOwnerId
JOIN Expertise Ex
ON UserEx.ExpertiseId = Ex.ExpertiseId
Readability of a query is a BIG help for yourself, and/or anyone assisting or following you. By not having the "on" clauses near the corresponding joins can be very confusing to follow.
Also, which is your PRIMARY table where the rest are lookup reference tables.
ADDITION PER COMMENT
Ok, so I updated a query which appears to have no context to the sample data and what you want in your post. That said, I would start with a list of hotels only and a count(*) of things per hotel so you can give SOME indication of how much stuff you have in detail. Something like
select
H.HotelID,
H.HotelName,
coalesce( MedSum.recs, 0 ) as MediaItems,
coalesce( LocSum.recs, 0 ) as NumberOfLocations,
coalesce( ComSum.recs, 0 ) as NumberOfLocations
from
Hotel H
LEFT JOIN
( select M.HotelID,
count(*) recs
from Media M
group by M.HotelID ) MedSum
on H.HotelID = MedSum.HotelID
LEFT JOIN
( select L.HotelID,
count(*) recs
from Location L
group by L.HotelID ) LocSum
on H.HotelID = LocSum.HotelID
LEFT JOIN
( select C.HotelID,
count(*) recs
from Comment C
group by C.HotelID ) ComSum
on H.HotelID = ComSum.HotelID
order by
H.HotelName
--- apply any limit per pagination
Now this will return every hotel at a top-level and the total count of things per the hotel per the individual counts which may or not exist hence each sub-check is a LEFT-JOIN. Expose a page of 20 different hotels. Now, as soon as one person picks a single hotel, you can then drill-into the locations, media and comments per that one hotel.
Now, although this COULD work, having to do these counts on an every-time query might get very time consuming. You might want to add counter columns to your main hotel table representing such counts as being performed here. Then, via some nightly process, you could re-update the counts ONCE to get them primed across all history, then update counts only for those hotels that have new activity since entered the date prior. Not like you are going to have 1,000,000 posts of new images, new locations, new comments in a day, but of 22,000, then those are the only hotel records you would re-update counts for. Each incremental cycle would be short based on only the newest entries added. For the web, having some pre-aggregate counts, sums, etc is a big time saver where practical.

How to sum employee paychecks from multiple jobs into one table

table featuring fictitious employee data, area ( in hectares (ha)) cleared (noted in french as superficie), rate for 1 hectare of cleared land on the specific lot (french:taux) and amount due( expr1) for that lot.
My problem here is that I want the total amount due for each Worker, not the amount due for each worker for each lot. Totals for Sirs Alain, Jacques, Paul, Roger and Tanguay should normally be 4066, 4082 , 5638, 5811 and 3131 , respectively.
My code so far is this
SELECT tbl_Employés.Num_deb, tbl_Employés.Prénom, tbl_Employés.Nom, tbl_Employés.Age, tbl_Employés.DEP, tbl_Employés.Expérience, tbl_Employés.Adresse, Tbl_terrain.superficie, Tbl_terrain.Taux, [superficie]*[taux] AS [Montant à payer]
FROM tbl_Employés INNER JOIN Tbl_terrain ON tbl_Employés.Num_deb = Tbl_terrain.Num_deb
ORDER BY tbl_Employés.Nom;
I have so far tried to use GROUP BY Numéro_terrain, which returns an error that my query does not include the specified expression ''Num_deb'' as a part of an aggregation fuction
I woul greatly appreciate any imput. I am very sorry if you have a hard time understanding some words, as I am doing my best to translate everything from french.
One method is to include all the columns in the GROUP BY that are not arguments to aggregation functions:
SELECT e.Num_deb, e.Prénom, e.Nom, e.Age, e.DEP, e.Expérience, e.Adresse,
SUM([superficie]*[taux]) AS [Montant à payer]
FROM tbl_Employés as e INNER JOIN
Tbl_terrain as t
ON e.Num_deb = t.Num_deb
GROUP BY e.Num_deb, e.Prénom, e.Nom, e.Age, e.DEP, e.Expérience, e.Adresse
ORDER BY e.Nom;

SQL - Remove Duplicates in Single Field

SELECT Company.CompanyName
,Student.Status
,Student.Level
,Student.PlacementYear
,Company.CompanyCode
,Company.HREmail
,Company.Telephone
,Company.HRContact
,PlacedStudents.DateAdded
FROM Student
RIGHT JOIN (Company INNER JOIN PlacedStudents
ON Company.CompanyCode = PlacedStudents.CompanyCode)
ON Student.StudentNo = PlacedStudents.StudentNo
WHERE (((Student.PlacementYear)=" & Year & "))
AND((Student.Status)<>'Still Seeking YOPE')
ORDER BY Company.CompanyName
I have this SQL Query which pulls HR Contacts from Companies where students are currently placed. However, there are multiple students at one company so when I run the query there are duplicates. I'm fairly new to SQL, I tried DISTINCT, however it didn't seem to do anything, the duplicates remained.
How can I remove duplicates in the CompanyCode field so that the Company only appears once when the query is run.
Below is an image of what happens when I run query. Hopefully this makes sense?
Any help would be appreciated.
This query should give you companies that have placed students:
SELECT Company.CompanyName
,Company.CompanyCode
,Company.HREmail
,Company.Telephone
,Company.HRContact
FROM Company
WHERE EXISTS (SELECT * FROM PlacedStudents INNER JOIN
Student ON Student.StudentNo = PlacedStudents.StudentNo
WHERE Company.CompanyCode = PlacedStudents.CompanyCode
AND Student.PlacementYear =" & Year & "
AND Student.Status <>'Still Seeking YOPE')
ORDER BY Company.CompanyName;
Your question is asking for HR Contacts from Companies where students are placed. I assume this means if you have 1, 2 or 1,000,000 students at a single company, you only want to see the company listed once?
Your current query is returning information from STUDENT and PLACEDSTUDENTS which is going to result in output like
COMPANY_A STUDENT01 .........
COMPANY_A STUDENT02 .........
COMPANY_A STUDENT03 .........
and so on.
If so, and taking a best guess (since I can't know what's in STUDENT or PLACEDSTUDENTS tables), try not including anything related to STUDENT in the SELECT.
SELECT DISTINCT Company.CompanyName, Company.CompanyCode, Company.HREmail,
Company.Telephone, Company.HRContact FROM
I'll be happy to help more if you can provide more information about the structure of the tables and some examples of data, AND what you actually want from the query.

SQL: Need to remove duplicate rows in query containing multiple joins

Note that I'm a complete SQL noob and in the process of learning. Based on Google searches (including searching here) I've tried using SELECT DISTINCT and GROUP BY but neither works, likely due to all of my joins (if anyone knows why they won't work exactly, that would be helpful to learn).
I need data from a variety of tables and below is the only way I know to do it (I just know the basics). The query below works fine but shows duplicates. I need to know how to remove those. The only hint I have right now is perhaps a nested SELECT query but based on research I'm not sure how to implement them. Any help at all would be great, thanks!
USE SQL_Contest
go
SELECT
CLT.Description AS ClockType,
CLK.SerialNumber AS JobClockSerial,
SIT.SiteNumber AS JobID,
SIT.[Name] AS JobsiteName,
SIT.Status AS SiteActivityStatus,
DHA.IssuedDate AS DHAIssuedDate, -- Date the clock was assigned to THAT jobsite
CLK.CreatedDate AS CLKCreatedDate, -- Date clock first was assigned to ANY jobsite
SES.ClockVoltage
FROM tb_Clock CLK
INNER JOIN tb_ClockType CLT
ON CLK.TypeID = CLT.ClockTypeID
INNER JOIN tb_DeviceHolderActivity DHA
ON CLK.ClockGUID = DHA.DeviceGUID
INNER JOIN tb_Site SIT
ON SIT.SiteGUID = DHA.HolderGUID
LEFT JOIN tb_Session SES
ON SES.ClockSerialNumber = CLK.SerialNumber
WHERE DHA.ReturnedDate IS NULL
ORDER BY SIT.[Name] ASC
EDIT: I will be reviewing these answers shortly, thank you very much. I'm posting the additional duplicate info per Rob's request:
Everything displays fine until I add:
LEFT JOIN tb_Session SES
ON SES.ClockSerialNumber = CLK.SerialNumber
Which I need. That's when a duplicate appears:
JobClock 2,500248E4,08-107,Brentwood Job,1,2007-05-04 13:36:54.000,2007-05-04 13:47:55.407,3049
JobClock 2,500248E4,08-107,Brentwood Job,1,2007-05-04 13:36:54.000,2007-05-04 13:47:55.407,3049
I want that info to only display once. Essentially this query is to determine all active jobsites that have a clock assigned to them, and that job only has one clock assigned to it, and it's only one jobsite, but it's appearing twice.
EDIT 2: Based on the help you guys provided I was able to determine they actually are NOT duplicates, and each session is independent, that is the only one that happened to have two sessions. So now I'm going to try to figure out how to only pull in information from the latest session.
If everything "works fine" until you add:
LEFT JOIN tb_Session SES
ON SES.ClockSerialNumber = CLK.SerialNumber
Then there must be more than one record in tb_Session for each CLK.SerialNumber.
Run the following query:
SELECT *
FROM tb_Session SES
WHERE ClockSerialNumber = '08-107'
There should be two records returned. You need to decide how to handle this (i.e. Which record do you want to use?), unless both rows from tb_Session contain identical data, in which case, should they?
You could always change your query to:
SELECT
CLT.Description AS ClockType,
CLK.SerialNumber AS JobClockSerial,
SIT.SiteNumber AS JobID,
SIT.[Name] AS JobsiteName,
SIT.Status AS SiteActivityStatus,
DHA.IssuedDate AS DHAIssuedDate, -- Date the clock was assigned to THAT jobsite
CLK.CreatedDate AS CLKCreatedDate, -- Date clock first was assigned to ANY jobsite
SES.ClockVoltage
FROM tb_Clock CLK
INNER JOIN tb_ClockType CLT
ON CLK.TypeID = CLT.ClockTypeID
INNER JOIN tb_DeviceHolderActivity DHA
ON CLK.ClockGUID = DHA.DeviceGUID
INNER JOIN tb_Site SIT
ON SIT.SiteGUID = DHA.HolderGUID
LEFT JOIN
(
SELECT DISTINCT ClockSerialNumber, ClockVoltage
FROM tb_Session
) SES
ON SES.ClockSerialNumber = CLK.SerialNumber
WHERE DHA.ReturnedDate IS NULL
ORDER BY SIT.[Name] ASC
As that should ensure that SES only contains one record for each unique combination of ClockSerialNumber and ClockVoltage
Take this example dataset:
Ingredient
IngredientId IngredientName
============ =========
1 Apple
2 Orange
3 Pear
4 Tomato
Recipe
RecipeId RecipeName
======== ==========
1 Apple Turnover
2 Apple Pie
3 Poached Pears
Recipe_Ingredient
RecipeId IngredientId Quantity
======== ============ ========
1 1 0.25
1 1 1.00
2 1 2.00
3 3 1.00
Note: Why the Apple Turnover has two lots of apple as ingredients, is neither here nor there, it just does.
The following query will return two rows for the "Apple Turnover" recipe, one row for the "Apple Pie" recipe and one row for the "Poached Pears" recipe, because there are two entries in the Recipe_Ingredient table for IngredientId 1. That's just what happens with a join..
SELECT I.IngredientName,
R.RecipeName
FROM Ingredient I
JOIN Recipe_Ingredient RI
ON I.IngredientId = RI.IngredientId
JOIN Recipe R
ON RI.recipeId = R.RecipeId
You could get this to return only one row by changing it to:
SELECT I.IngredientName,
R.RecipeName
FROM Ingredient I
JOIN Recipe_Ingredient RI
ON I.IngredientId = RI.IngredientId
JOIN Recipe R
ON RI.recipeId = R.RecipeId
GROUP BY I.IngredientName, R.RecipeName
Without more specifics regarding your data, it's hard to apply this to your specific scenario, but the walkthrough may help you understand where the "duplicates" are coming from as someone unfamiliar with SQL
The joins are not your problem. From your comments I will infer that what you are calling "duplicates" are not actual duplicates. If all columns values for 2 "duplicates" returned from the query matched, then either SELECT DISTINCT or GROUP BY would definitely eliminate them. So you should be able to find a solution by looking at your column definitions.
My best guess is that you're getting duplicates of for the same date which aren't really duplicates because the time component of the date doesn't match. To eliminate this problem, you can truncate the date fields to the date only using this technique:
DATEADD(DAY, DATEDIFF(DAY, 0, DHA.IssuedDate), 0) AS DHAIssuedDate,
DATEADD(DAY, DATEDIFF(DAY, 0, CLK.CreatedDate), 0) AS CLKCreatedDate,
If that doesn't work you might want to take a look at JobClockSerial: does this column belong in the query results?

SUM(a*b) not working

I have a PHP page running in postgres. I have 3 tables - workorders, wo_parts and part2vendor. I am trying to multiply 2 table column row datas together, ie wo_parts has a field called qty and part2vendor has a field called cost. These 2 are joined by wo_parts.pn and part2vendor.pn. I have created a query like this:
$scoreCostQuery = "SELECT SUM(part2vendor.cost*wo_parts.qty) as total_score
FROM part2vendor
INNER JOIN wo_parts
ON (wo_parts.pn=part2vendor.pn)
WHERE workorder=$workorder";
But if I add the costs of the parts multiplied by the qauntities supplied, it adds to a different number than what the script is doing. Help....I am new to this but if someone can show me in SQL I can modify it for postgres. Thanks
Without seeing example data, there's no way for us to know why you're query totals are coming out differently that when you do the math by hand. It could be a bad join, so you are getting more/less records than you expected. It's also possible that your calculations are off. Pick an example with the smallest number of associated records & compare.
My suggestion is to add a GROUP BY to the query:
SELECT SUM(p.cost * wp.qty) as total_score
FROM part2vendor p
JOIN wo_parts wp ON wp.pn = p.pn
WHERE workorder = $workorder
GROUP BY workorder
FYI: MySQL was designed to allow flexibility in the GROUP BY, while no other db I've used does - it's a source of numerous questions on SO "why does this work in MySQL when it doesn't work on db x...".
To Check that your Quantities are correct:
SELECT wp.qty,
p.cost
FROM WO_PARTS wp
JOIN PART2VENDOR p ON p.pn = wp.pn
WHERE p.workorder = $workorder
Check that the numbers are correct for a given order.
You could try a sub-query instead.
(Note, I don't have a Postgres installation to test this on so consider this more like pseudo code than a working example... It does work in MySQL tho)
SELECT
SUM(p.`score`) AS 'total_score'
FROM part2vendor AS p2v
INNER JOIN (
SELECT pn, cost * qty AS `score`
FROM wo_parts
) AS p
ON p.pn = p2v.pn
WHERE p2n.workorder=$workorder"
In the question, you say the cost column is in part2vendor, but in the query you reference wo_parts.cost. If the wo_parts table has its own cost column, that's the source of the problem.