I was tasked to look up several tickets in the database that hit certain criteria. But I think I am at the limitations of what SQL can handle. The below has an issue because all tickets that belong to company '1646' are like over 12k tickets for that customer alone...
So at first I thought about an inner join statement, but then I started to get a headache as things kept looping around itself. Below is the script that attempts to run, but then my database starts to smoke... And suffers read/write issues. The lag becomes very real and it is very clear to see it is from me pulling this query. The culprit:
SELECT
s.SR_Service_RecID as 'Ticket #',
t.Description as 'Description',
s.Summary as 'Summary Description',
d.Date_Created as 'Entered',
b.Board_Name as 'Board',
c.Company_ID as 'Company',
q.Description as 'Status',
p.SR_Severity_Name as 'Priority',
a.Description as 'Type',
z.Description as 'SubType',
s.Date_Closed as 'Closed'
d.SR_Detail_Notes_Markdown as 'Notes',
From
dbo.SR_Service as s,
dbo.SR_Type as t,
dbo.SR_Detail as d,
dbo.SR_Board as b,
dbo.Company as c,
dbo.SR_Status as q,
dbo.SR_Severity as p,
dbo.SR_Type as a,
dbo.SR_Subtype as z
WHERE
s.Company_RecID like '1646'
and s.Entered_By not like 'zadmin'
and s.Updated_By not like 'zadmin'
and s.Entered_By not like 'RESTAPI'
and s.Updated_By not like 'RESTAPI'
and s.Entered_By not like 'techautomate'
and s.Updated_By not like 'techautomate'
and s.Entered_By not like 'template%'
and s.Updated_By not like 'template%'
and s.Entered_By not like 'HelpDesk'
and s.Updated_By not like 'HelpDesk'
and s.Entered_By not like 'Email Connector'
and s.Updated_By not like 'Email Connector'
and d.SR_Detail_Notes_Markdown not like '%Assigned%'
ORDER BY
s.Date_Entered ASC;`
How can I refine this into a better query or change 8 of inner joins to make this work? How can I make am SQL script for?
First he Friendly names and then the primary key and foreign key relations:
ticket number = Service_RecID is the primary key in dbo.Service foriegn key in dbo.Detail
ticket type = SR_Type_RecID is the primary key in the dbo.Type foreign key in dbo.Service. But I need the description of that id which is in dbo.type.
Summary Description = is located in dbo.SR_Service the column header is Summary
Entered (is the date the ticket was entered) = located in dbo.SR_Detail under the column header Date_created.
Board (is the service board ticket is assigned to) = SR_Board_RecID primary key in dbo.SR_Board foreign key in SR_Service. But I need the column header Board_Name located in dbo.SR_Board.
Company = Company_RecID primary key in dbo.Config, but the foreign key in dbo.SR_Service
Status = SR_Status_RecID primary key dbo.SR_Status foreign key is located in dbo.SR_Service
Priority = SR_Severity_RecID primary key for dbo.SR_Severity foreign key is located in dbo.SR_Service. But I need SR_Severity_Name which is the column header in dbo.SR_Severity
type = SR_Type_RecID primary key in dbo.Type shares foreign key with dbo.Service. But I need the description associated with SR_Type_RecID located in dbo.SR_Type
subtype = SR_SubType_RecID primary key located in dbo.SR_subtype and the foreign key that is shared is under dbo.SR_service. But again I need the description that is under the dbo.SR_SubType.
closed = as it is located in the dbo.SR_Service under column header date_closed
notes = on the other hand is located in dbo.Detail under column header SR_Detail_Notes_Markdown and the only keys it shares across the database is a foreign key SR_Service_Rec_ID
I can’t seem to get the INNER JOIN statements to work properly.
INNER JOIN dbo.SR_Service.Service_RecID on dbo.SR_Detail.Service_RecID
INNER JOIN dbo.Type.SR_Type_RecID on dbo.SR_Service.SR_Type_RecID
INNER JOIN dbo.Type.Description on dbo.SR_Service.Type_Description
INNER JOIN dbo.SR_Board.SR_Board_RecID on dbo.Service.SR_BoardRecID
INNER JOIN dbo.Config.Company_RecID on dbo.Service.Company_RecID
INNER JOIN dbo.SR_Status.SR_Status_RecID on dbo.Service.SR_Status_RecID
INNER JOIN dbo.SR_SubType.SR_Type_RecID on dbo.Type.SR_Type_RecID
I think it is how I am declaring my FROM Statement...
Can I not just run singular database queries and have the results dump and append to a new database object?
The JOIN condition is how one table is related to another based on a common column. Aside from your specific query, think of orders.
An order is made by a customer. An order has details, order detail products are from a products table.
Having said that, you might want something like
select
c.customername,
o.orderdate,
od.qty,
p.productname
from
customer c
join orders o
on c.customerid = o.customerid
join orderDetails od
on o.orderid = od.orderid
join products p
on od.productid = p.productid
FEEDBACK FROM EDITS you provided in your original question
Now that you have provided respective primary key and foreign keys, we can help a little further. First, dont try to name your columns with spaces or special characters like 'Ticket #'. It is typically easier to name them readable in 'CamelCaseWhereUpperPerWord' is just an example. The output via whatever method should worry about the formatting of such header columns in output.
Next, when applying filters, such as your company number, if its a number, dont put it in quotes, leave it as a number for equality testing. In this case, you are looking for tickets for a single
company = 1646. I would ensure an index on the service table including that column as an index in its first position.
From your edited PK/FK, I have revised the query as below with embedded comments
SELECT
-- per ticket found
s.SR_Service_RecID TicketNumber,
-- dont worry about renaming Summary AS SummaryDescription,
-- let the OUTPUT process add whatever column headers is more common approach
-- just get the column and get it to work first, then fine-tune it
s.Summary,
s.Date_Closed Closed,
-- dont worry for now about specific column order, I am trying to match
-- the hierarchy of data trying to acquire. You want for a specific company,
-- so I am just putting that up front for now.
c.Company_ID Company,
-- description from the TYPE table
t.Description type,
-- pull from sub-type of the type
st.Description SubType,
-- now I can pull columns from the SR_Detail table
d.Date_Created Entered,
d.SR_Detail_Notes_Markdown Notes,
-- now any columns from the SR_Board table
b.Board_Name Board,
-- columns from the status table
q.Description Status,
p.SR_Severity_Name Priority
From
-- or is this table SUPPOSED to be Service vs SR_Service
SR_Service as s
-- first, joining to the config table so you can get the descriptive company "name", such as your "Company_ID"
JOIN Config as c
on s.Company_RecID = c.Company_RecID
-- now join the outer hierarchy SR_Service to the SR_Type on its PK/FK relationship
join SR_Type as t
on s.SR_Type_RecID = t.SR_Type_RecID
-- changing the subtype to a LEFT-JOIN in case a sub-type does not exist
LEFT JOIN SR_Subtype as st
on s.SR_SubType_RecID = st.SR_SubType_RecID
-- now join the outer hierarchy SR_Service to the SR_Detail on its PK/FK relationship
-- or is this table SUPPOSED to be Detail vs SR_Detail
JOIN SR_Detail as d
on s.Service_RecID = d.Service_RecID
-- doing a LEFT-JOIN since an entry may NOT be assigned to a board (yet).
-- otherwise the ticket will be excluded from final list if no such board assignment
LEFT JOIN SR_Board as b
on s.SR_Board_RecID = b.SR_Board_RecID
-- etc., similar joins to each other lookup table for clear descriptions based on given PK/FK relationship
JOIN SR_Status as q
on s.SR_Status_RecID = q.SR_Status_RecID
JOIN SR_Severity as p
on s.SR_Severity_RecID = p.SR_Severity_RecID
WHERE
-- NOW, you can apply your filtering conditions here as you have them
s.Company_RecID = 1646
and s.Entered_By not like 'zadmin'
and s.Updated_By not like 'zadmin'
and s.Entered_By not like 'RESTAPI'
and s.Updated_By not like 'RESTAPI'
and s.Entered_By not like 'techautomate'
and s.Updated_By not like 'techautomate'
and s.Entered_By not like 'template%'
and s.Updated_By not like 'template%'
and s.Entered_By not like 'HelpDesk'
and s.Updated_By not like 'HelpDesk'
and s.Entered_By not like 'Email Connector'
and s.Updated_By not like 'Email Connector'
and d.SR_Detail_Notes_Markdown not like '%Assigned%'
ORDER BY
s.Date_Entered ASC;
Now that you have a full query, in the future, take one piece at a time. Look at what you wanted. All tickets associated with one customer. Query just that. As you have a table (or alias), get all the columns you expect from that one before moving on. Ex:
select
s.SR_Service_RecID TicketNumber,
s.Summary,
s.Date_Closed Closed
from
SR_Service s
where
s.Company_RecID = 1646
Great, this gets you the immediate result of the tickets. But now you want more stuff. So, one table at a time, do a join. How does the second table relate to the first. I always try to list my primary (in this case your service table) on the left (or first position) JOINING a second table (right-side) based on what FK/PK relationship. In this case, you want the in-the-clear company name from the Config table. So, get that extra column based on the join itself.
select
s.SR_Service_RecID TicketNumber,
s.Summary,
s.Date_Closed Closed,
-- and now columns from next table
c.Company_ID Company
from
SR_Service s
JOIN Config as c
on s.Company_RecID = c.Company_RecID
where
s.Company_RecID = 1646
Continue adding one table at a time and one WHERE clause at a time until the entire query is done. In SQL-Server, by doing a
SELECT TOP 10 (rest of query)
will result the list to only 10 records. This way, you can sample "Does this query work as written?" Do you get an answer? Have you botched the command already? Fix it early one piece at a time. Column between each column retrieved. Do I have the proper JOIN condition between the two tables? then move on.
Hopefully this detailed example of your database scenario will help you learn to write queries easier. Also see how to better list your table structures (ALL RELEVANT COLUMNS) to help get better responses vs us trying to guess at column names in tables.
As Martin Smith says, you need to define the table joins. As the query stands now, any results would be useless.
To do this, you must first understand the database schema. More specifically, the relationship between the entities (= tables). For this you need to know and understand the business domain and how it is represented in the tables.
The SQL Server experts from this site will not be able to do this for you without the knowledge of the business domain.
After you have achieved the above you can deduce the correct joins from the database schema and improve your query draft accordingly.
Related
I just started using SQL and I need some help. I have 4 tables in a database. All four are connected with each other. I need to find the amount of unique transactions but can't seem to find it.
Transactions
transaction_id pk
name
Partyinvolved
transaction.id pk
partyinvolved.id
type (buyer, seller)
PartyCompany
partyinvolved.id
Partycompany.id
Companies
PartyCompany.id pk
sector
pk = primary key
The transaction is unique if the conditions are met.
I only need a certain sector out of Companies, this is condition1. Condition2 is a condition inside table Partyinvolved but we first need to execute condition1. I know the conditions but do not know where to put them.
SELECT *
FROM group
INNER JOIN groupB ON groupB.group_id = group.id
INNER JOIN companies ON companies.id = groupB.company_id
WHERE condition1 AND condition2 ;
I want to output the amount of unique transactions with the name.
It is a bit unclear what you are asking as your table definitions look like your hinting at column meanings more than names such as partycompany.id you are probably meaning the column that stores the relationship to PartyCompany column Id......
Anyway, If I follow that logic and I look at your questions about wanting to know where to limit the recordsets during the join. You could do it in Where clause because you are using an Inner Join and it wont mess you your results, but the same would not be true if you were to use an outer join. Plus for optimization it is typically best to add the limiter to the ON condition of the join.
I am also a bit lost as to what exactly you want e.g. a count of transactions or the actual transactions associated with a particular sector for instance. Anyway, either should be able to be derived from a basic query structure like:
SELECT
t.*
FROM
Companies co
INNER JOIN PartyCompancy pco
ON co.PartyCompanyId = pco.PartyCompanyId
INNER JOIN PartyInvolved pinv
ON pco.PartyInvolvedId = pinv.PartyInvolvedId
AND pinv.[type] = 'buyer'
INNER JOIN Transactions t
ON ping.TransactionId = t.TransactionId
WHERE
co.sector = 'some sector'
I have 3 tables in my database.
The first table is "Ordenes", in this table i have all the orders that the users create in the website, this table got information like: FechaFinal, FechaInicial, NoOrden, Cantidad, and Estado.
I have another table called "Cables", in this table i save all the cable that the users register per order.
For example, if i have a order row and the Cantidad says that is 200, so the user need register 200 cables to this order.
The Cables table have information like: Serial, IdOrden, and IdOperation.
The IdOperation is a foreign key of the Operations Tables, in this table i save information like: Name of operation, and its all.
So i want to do a sql query that show me this information:
FechaInicial (From Order Table), Fechafinal (From Order Table), NoOrden (From Order Table), Material (From Order Table), Cantidad (From Order Table), and Performed (This is a count of all cables that i have in my Cables Table for some Order)
I have it, and it works, but i want that the query ONLY COUNT the cables that doesn't are in some operation called 'Scrap'.
I have this SQL Query, and it works, but it also is counting the cables that are in the 'Scrap' Operation.
SELECT o.FechaInicial, o.FechaFinal, o.NoOrden, o.Material, o.Cantidad, COUNT(c.IdCable) as 'Hechos', o.Estado
FROM Ordenes o
LEFT JOIN Cables c ON o.IdOrden = c.IdOrden
LEFT JOIN Operaciones op ON c.IdOperacion = op.IdOperacion AND op.Nombre NOT IN ('Scrap')
GROUP BY o.FechaInicial, o.Fechafinal, o.NoOrden, o.Material, o.Cantidad, o.Estado;
I want to show ALL orders, even if a order doesn't have cables yet.
Change the count to COUNT(op.Nombre) or COUNT(op.idOperacion) if Nombre can be NULL.
The left join keeps all rows, even those that have scrap. The best solution is to count the primary key or join key from the last table. So, I would recommend:
SELECT o.FechaInicial, o.FechaFinal, o.NoOrden, o.Material, o.Cantidad,
COUNT(op.IdOperacion) as Hecho, o.Estado
FROM Ordenes o LEFT JOIN
Cables c
ON o.IdOrden = c.IdOrden LEFT JOIN
Operaciones op
ON c.IdOperacion = op.IdOperacion AND op.Nombre NOT IN ('Scrap')
GROUP BY o.FechaInicial, o.Fechafinal, o.NoOrden, o.Material, o.Cantidad, o.Estado;
This counts only "matching" rows in Operaciones.
Note: If you count a data column, you might be missing rows where that value is NULL in the original table. That might be a good thing, depending on the intention of the query. In general, it is safer to count something that cannot be NULL when a match occurs.
I have a new app that I'm trying to figure out data for. Is for recreational vehicle ads and my idea is:
Advertisement - contains AdID plus common items like price, etc.),
RV - contains motorhome specific info,
TravelTrailer - contains travel trailer info
If an ad joins with one or the other conditional on the AdID being found in one of my "secondary" tables (traveltrailer or RV) I have seen queries online like the following:
select
E.EmployeeName, coalesce(s.store,o.office) as Location
from
Employees E
left outer join
Stores S on ...
left outer join
Offices O on ...
Problem is the travel trailer and RV tables will contain some exclusive items that don't exist in the other. As a simple example the tables could be like-
Trailer - length, sleeping capacity
RV - length, sleeping capacity, motor
Using the left join approach above sometimes I might retrieve the motor column (if it's an RV) and sometimes I might not (if it's a travel trailer). I can't figure out how to do that.
I could pass in a type (RV or TravelTrailer) and run one of two different queries based on type but I'd like to just pass in an AdID and get my info with that. I could also do two queries, one to get the ad info using the AdID and then a 2nd one based on the type that comes back from the advertisement table. I'd just like to figure out how to do this in one pull if possible.
Thank you!
I would rethink the way you are storing the data to begin with.
Combine the RV table and TravelTrailer tables as follows:
products (product_id, product_type_id, product_attribute, attribute_value)
Where product_type_id references id on table product_types: (FK constraint)
product_types (id, name)
Ie. you might have RV be id #1 and motor homes id #2.
and where product_attribute_id references id on table product_attributes: (FK constraint)
product_attributes (id, name)
Ie. you might have weight be id #1, length be id #2, sleep capacity be id #3, etc.
This way you will not have some products in table X, some products in table Y, others in Z, etc. and you can write queries more normally. If your queries are constantly more complex than they need to be, it's usually design related.
One approach would be this:
select
Advertisement.AdId
,Advertisement.Price
,coalesce(Trailer.Length,RV.Length) as Length
,coalesce(Motor,"") as Motor
-- other fields as desired
from Advertisement
left join Trailer on Trailer.AdID = Advertisement.AdId
left join RV on RV.AdID = Advertisement.AdId;
Above is my schema. What you can't see in tblPatientVisits is the foreign key from tblPatient, which is patientid.
tblPatient contains a distinct copies of each patient in the dataset as well as their gender. tblPatientVists contains their demographic information, where they lived at time of admission and which hospital they went to. I chose to put that information into a separate table because it changes throughout the data (a person can move from one visit to the next and go to a different hospital).
I don't get any strange numbers with my queries until I add tblPatientVisits. There are just under one millions claims in tblClaims, but when I add tblPatientVisits so I can check out where that person was from, it returns over million. I thinkthis is due to the fact that in tblPatientVisits the same patientID shows up more than once (due to the fact that they had different admission/dischargedates).
For the life of me I can't see where this is incorrect design, nor do I know how to rectify it beyond doing one query with count(tblPatientVisits.PatientID=1 and then union with count(tblPatientVisits.patientid)>1.
Any insight into this type of design, or how I might more elegantly find a way to get the claimType from tblClaims to give me the correct number of rows with I associate a claim ID with a patientID?
EDIT: The biggest problem I'm having is the fact that if I include the admissionDate,dischargeDate or the patientStatein the tblPatient table I can't use the patientID as a primary key.
It should be noted that tblClaims are NOT necessarily related to tblPatientVisits.admissionDate, tblPatientVisits.dischargeDate.
EDIT: sample queries to show that when tblPatientVisits is added, more rows are returned than claims
SELECT tblclaims.id, tblClaims.claimType
FROM tblClaims INNER JOIN
tblPatientClaims ON tblClaims.id = tblPatientClaims.id INNER JOIN
tblPatient ON tblPatientClaims.patientid = tblPatient.patientID INNER JOIN
tblPatientVisits ON tblPatient.patientID = tblPatientVisits.patientID
more than one million query rows returned
SELECT tblClaims.id, tblPatient.patientID
FROM tblClaims INNER JOIN
tblPatientClaims ON tblClaims.id = tblPatientClaims.id INNER JOIN
tblPatient ON tblPatientClaims.patientid = tblPatient.patientID
less than one million query rows returned
I think this is crying for a better design. I really think that a visit should be associated with a claim, and that a claim can only be associated with a single patient, so I think the design should be (and eliminating the needless tbl prefix, which is just clutter):
CREATE TABLE dbo.Patients
(
PatientID INT PRIMARY KEY
-- , ... other columns ...
);
CREATE TABLE dbo.Claims
(
ClaimID INT PRIMARY KEY,
PatientID INT NOT NULL FOREIGN KEY
REFERENCES dbo.Patients(PatientID)
-- , ... other columns ...
);
CREATE TABLE dbo.PatientVisits
(
PatientID INT NOT NULL FOREIGN KEY
REFERENCES dbo.Patients(PatientID),
ClaimID INT NULL FOREIGN KEY
REFERENCES dbo.Claims(ClaimID),
VisitDate DATE
, -- ... other columns ...
, PRIMARY KEY (PatientID, ClaimID, VisitDate) -- not convinced on this one
);
There is some redundant information here, but it's not clear from your model whether a patient can have a visit that is not associated with a specific claim, or even whether you know that a visit belongs to a specific claim (this seems like crucial information given the type of query you're after).
In any case, given your current model, one query you might try is:
SELECT c.id, c.claimType
FROM dbo.tblClaims AS c
INNER JOIN dbo.tblPatientClaims AS pc
ON c.id = pc.id
INNER JOIN dbo.tblPatient AS p
ON pc.patientid = p.patientID
-- where exists tells SQL server you don't care how many
-- visits took place, as long as there was at least one:
WHERE EXISTS (SELECT 1 FROM dbo.tblPatientVisits AS pv
WHERE pv.patientID = p.patientID);
This will still return one row for every patient / claim combination, but it should only return one row per patient / visit combination. Again, it really feels like the design isn't right here. You should also get in the habit of using table aliases - they make your query much easier to read, especially if you insist on the messy tbl prefix. You should also always use the dbo (or whatever schema you use) prefix when creating and referencing objects.
I'm not sure I understand the concept of a claim but I suspect you want to remove the link table between claims and patient and instead make the association between patient visit and a claim.
Would that work out better for you?
The database is quite simple. Below there is a part of a schema relevant to this question
ROUND (round_id, round_number)
TEAM (team_id, team_name)
MATCH (match_id, match_date, round_id)
OUTCOME (team_id, match_id, score)
I have a problem with query to retrieve data for all matches played. The simple query below gives of course two rows for every match played.
select *
from round r
inner join match m on m.round_id = r.round_id
inner join outcome o on o.match_id = m.match_id
inner join team t on t.team_id = o.team_id
How should I write a query to have the match data in one row?
Or maybe should I redesign the database - drop the OUTCOME table and modify the MATCH table to look like this:
MATCH (match_id, match_date, team_away, team_home, score_away, score_home)?
You can almost generate the suggested change from the original tables using a self join on outcome table:
select o1.team_id team_id_1,
o2.team_id team_id_2,
o1.score score_1,
o2.score score_2,
o1.match_id match_id
from outcome o1
inner join outcome o2 on o1.match_id = o2.match_id and o1.team_id < o2.team_id
Of course, the information for home and away are not possible to generate, so your suggested alternative approach might be better after all. Also, take note of the condition o1.team_id < o2.team_id, which gets rid of the redundant symmetric match data (actually it gets rid of the same outcome row being joined with itself as well, which can be seen as the more important aspect).
In any case, using this select as part of your join, you can generate one row per match.
you fetch 2 rows for every matches played but team_id and team_name are differents :
- one for team home
- one for team away
so your query is good
Using the match table as you describe captures the logic of a game simply and naturally and additionally shows home and away teams which your initial model does not.
You might want to add the round id as a foreign key to round table and perhaps a flag to indicate a match abandoned situation.
drop outcome. it shouldn't be a separate table, because you have exactly one outcome per match.
you may consider how to handle matches that are cancelled - perhaps scores are null?