How to SELECT infinity deep loop data with SELF JOIN - sql

Trying to project effective DataBase:
We look at advertisements, where sellers post their phone numbers, sellers can have more than one phone number, and sellers can post their phones in different ways...
simple image to clearly understand:
I want to find ALL advertisements, phoneS and target seller knowing just one phone [phone_1|phone_2|...|phone_4]!
Here is the table structure I want to use:
Where you can notice:
Advertisement_1010001 has THREE phones: ..0001, ..0002, ..0003.
Advertisement_1010003 has TWO phones: ..0003, ..0004.
Advertisement_1010004 has ONE phone: ..0004.
(all advs. foregoing were published with ONE seller, because ALL phones LINKED!)
Advertisement_1010005 has TWO phones, but it belongs it belongs to another seller.
All is good, but how can I "SELECT phone, adver_num WHERE my_phone IN (head & tail_phones)" using just ONE query?
I am sure, self join will help me, but the way I am using it now is not very appropriate:
SELECT a1.`advert_site_num`,
a1.`head_phone`
FROM `test_table` a1
LEFT JOIN `test_table` a2 ON a1.`tail_phones` = a2.`head_phone`
UNION
SELECT a3.`advert_site_num`,
a3.`tail_phones`
FROM `test_table` a3
LEFT JOIN `test_table` a4 ON a3.`tail_phones` = a4.`head_phone`
ORDER BY `advert_site_num`, `head_phone`;
returns all records linked by phone whithout filtering with searching phone

why don't you just filter with where? I'm not sure to understand your problem:
SELECT `advert_site_num`, GROUP_CONCAT(`phone` SEPARATOR ',') FROM (
SELECT `advert_site_num`,
`tail_phones` AS `phone`
FROM `test_table`
WHERE a1.`tail_phones` = myphone
UNION
SELECT `advert_site_num`,
`head_phone` AS `phone`
FROM `test_table`
WHERE a1.`head_phone` = myphone
)
GROUP BY `advert_site_num`;

Related

SQL - Returning fields based on where clause then joining same table to return max value?

I have a table named Ticket Numbers, which (for this example) contain the columns:
Ticket_Number
Assigned_Group
Assigned_Group_Sequence_No
Reported_Date
Each ticket number could contain 4 rows, depending on how many times the ticket changed assigned groups. Some of these rows could contain an assigned group of "Desktop Support," but some may not. Here is an example:
Example of raw data
What I am trying to accomplish is to get the an output that contains any ticket numbers that contain 'Desktop Support', but also the assigned group of the max sequence number. Here is what I am trying to accomplish with SQL:
Queried Data
I'm trying to use SQL with the following query but have no clue what I'm doing wrong:
select ih.incident_number,ih.assigned_group, incident_history2.maxseq, incident_history2.assigned_group
from incident_history_public as ih
left join
(
select max(assigned_group_seq_no) maxseq, incident_number, assigned_group
from incident_history_public
group by incident_number, assigned_group
) incident_history2
on ih.incident_number = incident_history2.incident_number
and ih.assigned_group_seq_no = incident_history2.maxseq
where ih.ASSIGNED_GROUP LIKE '%DS%'
Does anyone know what I am doing wrong?
You might want to create a proper alias for incident_history. e.g.
from incident_history as incident_history1
and
on incident_history1.ticket_number = incident_history2.ticket_number
and incident_history1.assigned_group_seq_no = incident_history2.maxseq
In my humble opinion a first error could be that I don't see any column named "incident_history2.assigned_group".
I would try to use common table expression, to get only ticket number that contains "Desktop_support":
WITH desktop as (
SELECT distinct Ticket_Number
FROM incident_history
WHERE Assigned_Group = "Desktop Support"
),
Than an Inner Join of the result with your inner table to get ticket number and maxSeq, so in a second moment you can get also the "MAXGroup":
WITH tmp AS (
SELECT i2.Ticket_Number, i2.maxseq
FROM desktop D inner join
(SELECT Ticket_number, max(assigned_group_seq_no) as maxseq
FROM incident_history
GROUP BY ticket_number) as i2
ON D.Ticket_Number = i2.Ticket_Number
)
SELECT i.Ticket_Number, i.Assigned_Group as MAX_Group, T.maxseq, i.Reported_Date
FROM tmp T inner join incident_history i
ON T.Ticket_Number = i.Ticket_Number and i.assigned_group_seq_no = T.maxseq
I think there are several different method to resolve this question, but I really hope it's helpful for you!
For more information about Common Table Expression: https://www.essentialsql.com/introduction-common-table-expressions-ctes/

Query SQL,find the teams that do not have any athlete who reached the finish line of a flat stage first or second

I'm trying to make a query that asks me to find the teams that do not have any athlete who reached the finish line of a flat stage first or second.
These are the tables:
cyclist (cyclist_id: Int, name_cyclist: string, team: string of three letters, country: three-letter string)
tape (_name: string, km: int, type: 'flat' or 'high_mountain' or 'medium_mountain' or 'chronometro_a_team' or 'chronometro_individual' or 'time_trial')
arrival_order (cyclist_id:int ; tape_name:string, order: int): where cyclist_id (resp, tape_name) is an external key that refers to cyclist (resp, tape);
This is the script that I managed to do. The problem is that it returns me the name of a team if for example there are 2 athletes and one is ranked among the top 2 and the other is not. How can I solve this problem?
SELECT DISTINCT c.team
FROM arrival_order oa
JOIN tape s ON oa.tape_name = s.tape_name
JOIN cyclist c ON oa.cyclist_id = c.cyclist_id
WHERE oa.order>2 AND s.type='flat';
Use aggregation and do the check on order in the HAVING clause:
SELECT c.team
FROM arrival_order oa JOIN
tape s
ON oa.tape_name = s.tape_name JOIN
cyclist c
ON oa.cyclist_id = c.cyclist_id
WHERE s.type = 'flat'
GROUP BY c.team
HAVING MIN(oa.order) > 2 ;
First, for proper normalization, there should be a table for teams.
CREATE TABLE teams AS SELECT DISTINCT team FROM cyclists;
ALTER TABLE teams ADD PRIMARY KEY (team);
Then table cyclists should refer to it by id and not name, but let's skip that.
find the teams that do not have any athlete who reached the finish line of a flat stage first or second.
Well that sounds like a NOT EXISTS:
SELECT * FROM teams
WHERE NOT EXISTS(
SELECT * FROM arrival_order
JOIN cyclists ON (cyclists.id=arrival_order.cyclist_id)
JOIN tape ON (tape.name=arrival_order.tape_name)
WHERE arrival_order.order <= 2
AND tape.type = 'flat'
AND cyclists.team = team.name
)
You can also use a LEFT JOIN, but that would be more complicated, and postgres will probably turn your NOT EXISTS into a LEFT JOIN for optimization anyway.
Note if a team has no cyclists, or its cyclists did not participate in any flat races, the team will still be in the result... because that's what was asked in the question: "team does not have any athlete who reached the finish line of a flat stage first or second."
If you want to find the teams that have athletes who reached the finish line of a flat stage, but were not ranked first or second, then you should use a JOIN instead of a NOT EXIST, and put order>2 somewhere in the WHERE.

How can I access a selected column from my first select-statement in my third-level subslect?

I have a table "Bed" and a table "Component". Between those two I have a m:n relation and the table "BedComponent", where I store the Bed-ID and the Component-ID.
Every Component has a price. And now I want to write a select-statement that gives me the sum of prices for a certain bed.
This is what I have:
SELECT Bed.idBed, Bed.name, SUM(src.price) AS summe, Bed.idCustomer
FROM Bed,
(SELECT price
FROM dbo.Component AS C
WHERE (C.idComponent IN
(SELECT idComponent
FROM dbo.BedComponent AS BC
WHERE 1 = BC.idBed))) AS src
GROUP BY dbo.Bed.idBed, dbo.Bed.name, dbo.Bed.idCustomer;
This statement works. But of course I don't want to write the bed-ID hard coded into my select as it will always calculate the price for bed 1. Instead of the "1" i want to have the current bed-id.
I work with MS SQL Server
Thanks for your help.
I think you want:
select b.idBed, b.name, SUM(src.price) AS summe, b.idCustomer
from bed b join
bedcomponent bc
on b.idBed = bc.idBed join
component c
on c.idComponent = bc.idComponent
group by b.idBed, b.name, b.idCustomer;
The idCustomer looks strange to me in the select and group by, but I don't know what you are trying to achieve.
Also note the use of table aliases, which make the query easier to write and to read.

Way to combine filtered results using LIKE

I have a many to many relationship between people and some electronic codes. The table with the codes has the code itself, and a text description of the code. A typical result set from a query might be (there are many codes that contain "broken" so I feel like it's better to search the text description rather than add a bunch of ORs for every code.)
id# text of code
1234 broken laptop
1234 broken mouse
Currently the best way for me to get a result set like this is to use the LIKE%broken% filter. Without changing the text description, is there any way I can return only one instance of a code with broken? So in the example above the query would only return 1234 and broken mouse OR broken laptop. In this scenario it doesn't matter which is returned, all I'm looking for is the presence of "broken" in any of the text descriptions of that person's codes.
My solution at the moment is to create a view that would return
`id# text of code
1234 broken laptop
1234 broken mouse`
and using SELECT DISTINCT ID# while querying the view to get only one instance of each.
EDIT ACTUALLY QUERY
SELECT tblVisits.kha_id, tblICD.descrip, min(tblICD.Descrip) as expr1
FROM tblVisits inner join
icd_jxn on tblVisits.kha_id = icd_jxn.kha)id inner join tblICD.icd_fk=tblICD.ICD_ID
group by tblVisits.kha_id, tblicd.descrip
having (tblICD.descrip like n'%broken%')
You could use the below query to SELECT the MIN code. This will ensure only text per id.
SELECT t.id, MIN(t.textofcode) as textofcode
FROM table t
WHERE t.textofcode LIKE '%broken%'
GROUP BY t.id
Updated Actual Query:
SELECT tblVisits.kha_id,
MIN(tblICD.Descrip)
FROM tblVisits
INNER JOIN icd_jxn ON tblVisits.kha_id = icd_jxn.kha)id
INNER JOIN tblicd ON icd_jxn.icd_fk = tbl.icd_id
WHERE tblICD.descrip like n'%broken%'
GROUP BY tblVisits.kha_id

Oracle SQL get column value associated with max(count())

I have the following query. What results is two coloums, oakid and max(count(rating)). What I want is to have two columns, but instead of actually having the max(count(rating)), I want the rating associated with the max(count(rating)). How can I modify my query to give me this?
select oakid,
(select max(count(rating))
from climbs, routes
where climbs.routename = routes.name
and climbs.climberid = oakid group by routes.rating)
as skill
from climbers;
For example, if I have ratings "hard, hard, easy, easy, easy, medium", the max(count(rating)) will show "3", since there are 3 "easy" ratings, but I want it to show "easy", not "3".
It sounds as though you want the statistical mode (most frequently occurring) rating for each oakid or climberid. Oracle has a handy function to do this for us called STATS_MODE:
SELECT c.climberid AS oakid, STATS_MODE(r.rating) AS skill
FROM climbs c
INNER JOIN routes r ON (c.routename = r.name)
GROUP BY c.climberid;
try the following:
select oakid,
(select rating
from climbs, routes
where climbs.routename = routes.name
and climbs.climberid = oakid
group by routes.rating
having max(count(rating)) = count(rating))
as skill
from climbers