Replacing id's in 2 columns from same table with names from second table - sql

I am trying to select all Song1 and Song2 rows from my Connections table but instead of showing the id number, I want to use my Songs table to replace the number with the Name of the song
This is the things I have tried and what I got:
select Name,Name
from Connections
JOIN Songs
ON Songs.SongID = CAST(Connections.Song1 AS varchar)
JOIN Connections as Connections2
ON Songs.SongID = CAST(Connections2.Song2 AS varchar);
^ This gives me 2 columns that are the same that only shows song 6 (because it is used in both song1 and song2)
select Name from Songs
JOIN Connections
ON Songs.SongID = connections.Song1
select Name from Songs
JOIN Connections
ON Songs.SongID = connections.Song2
^ The top one gives the desired outcome for the Song1 Column and the bottom one gives the desired outcome for the Song2 column but I can't figure out how to join them.
I am using Microsoft SQL Server Management Studio and new to SQL
Connections table:
Song1
Song2
1
2
3
4
5
6
6
7
Songs table:
SongId
Name
1
Turning Back
2
Reason
3
Solar System
4
Generator
5
Siren
6
Circles
7
Bunker
The desired output for the first 4 rows would be:
Song1
Song2
Turning Back
Reason
Solar System
Generator
Siren
Circles
Cirles
Bunker

You want two joins:
select s1.Name, s2.Name
from connections c join
songs s1
on s1.SongID = c.song1 join
songs s2
on s2.SongId = c.song2;
The following applies to the original question and was apparently a propos given the edits.
Your data model and query is a little confusing:
Why are you converting song1 to a string? That should not be necessary. Columns that link two tables should have the same type -- and be declared as foreign keys.
Why is a column called name stored as a number?
These questions don't need to be answered. They are just feedback on the design of the data.

The below query is for MySQL and I am sure this will work in MS SQL too. We are using nested query here, the output of nested query will give SongId to extract the name of the Songs from SongTable.
select SongTable.Name from SongTable
where SongId in (select Song1,Song2 from ConnectionTable where ConnectionId="?");

Related

Getting ranges of arbitrary strings in SQL based on sequence dictated in a separate table

Consider the following dataset (may look weird but want to land my point that the strings are arbitrary):
Table A
TicketId
StartAnimal
EndAnimal
1
Monkey
Bee
1
Lion
Buffalo
Table B
Animal
Sequence
Monkey
1
Zebra
2
Bee
3
Turtle
4
Lion
5
Buffalo
6
Is it possible to retrieve the animals that correspond to Ticket ID 1 based on the different "ranges" in each of its rows? For example,for Ticket ID 1 the following animals should be retrieved: Monkey, Zebra, Bee, Lion, Buffalo.
As you can see the animal strings themselves have no order logic to it, but the sequence can be leveraged for it. I'm just failing to come up with how to reference it for each row in a single query.
Edit
As an edge case, sometimes the EndAnimal might not even have a sequence to start with, in which case only the StartAnimal should be returned. As an example, assuming Bee is not in the sequence table, we should only get Monkey, Lion and Buffalo. Is that something SQL can handle?
Thanks!
There are numerous ways, one such way is to inner join the tables to find the corresponding start and end sequences and then find those rows that qualify:
with s as (
select bs.Sequence s1, IsNull(be.sequence,1) s2, a.ticketId
from a left join b bs on bs.animal = a.StartAnimal
left join b be on be.Animal = a.EndAnimal
)
select b.Animal
from b
join s on b.Sequence >=s1 and b.Sequence <= s2
where s.ticketId = 1
order by b.Sequence;
Example Fiddle

Postgresql: Values of multiple rows in one row

I have the following database:
Car: {[CarID, HorsePower, Brand, HeadDesigner]}
DesignsCar:{[CarID, DesID]}
Designer:{[DesID, Name]}
You should note that while every Car has only 1 HeadDesigner, multiple people can design cars (as in work on them).
Say I have 10 cars in my database. For CarID (1..9) only one DesID per CarID in DesignsCar.
However, for carID 10 we have 3 people working on it (carID has 3 entries in DesignsCar because 3 people worked on it).
Say I do this:
select *
from car c
left outer join designscar ds on c.carid = ds.carid
left outer join designer d on frb.persnr = r.persnr
This gives me 12 rows, when I only want 10. The reason why this gives me 12 rows should be clear: for carID 10 we have 3 people working on it (carID has 3 entries in DesignsCar because 3 people worked on it).
I hope I've done a good job explaining this problem, so here comes my question:
How do I modify the query above so I get 10 Rows. For CarID 10 I'd like the 3 designers to be written in one column (like, comma separated but anything works as long it's in one column).
Is that possible?
You need to aggregate the values. Here is one possibility:
select c.*,
array_agg(d.name) as designer_names
from car c left outer join
designscar ds
on c.carid = ds.carid left outer join
designer d
on frb.persnr = r.persnr
group by c.carid ; -- allowed assuming `carid` is the primary key

Find 'Most Similar' Items in Table by Foreign Key

I have a child table with a number of charact/value pairs for a given 'material' (MaterialID). Any material can have a number of charact values and may have several of the same name (see id's 2,3).
The table has a large number of records (8+ million). What I'm trying to do is find the materials that are the most similar to a supplied material. That is, when I supply a MaterialID, I would like an ordered list of the most similar other materials (those with the most matching charact/value pairs).
I've done some research but, I may be missing some key terms or just not conceptualizing the problem correctly.
Any hints as to how to go about this would be very much appreciated.
ID MaterialID Charact Value
1 1 ROT_DIR CCW
2 1 SPECIAL_FEATURE CATALOG_CP
3 1 SPECIAL_FEATURE CHROME
4 1 SCHEDULE 80
5 2 BEARING_TYPE SB
6 2 SCHEDULE 80
7 3 ROT_DIR CCW
8 3 SPECIAL_FEATURE CATALOG_HSB
9 3 BEARING_TYPE SP
10 4 NDE_STYLE W_FAN
11 4 BEARING_TYPE SB
12 4 ROT_DIR CW*
You can do this with a self join:
select t.materialid, count(*) as nummatches
from t join
t tmat
on t.Charact = tmat.Charact and t.value = tmat.value
where tmat.materialid = #MaterialId
group by t.materialid
order by nummatches desc;
Notes:
You might want to remove the specified material, by adding where t.MaterialId <> tmat.MaterialId to the where clause.
If you want all materials, then make the join a left join and move the where condition to the on clause.
If you want only one material with the most matches, use select top 1.
If you want all materials with the most matches when there are ties, use `select top (1) with ties.

Can you use data that you got from a query in another query?

Say I've got some data from a SELECT query. Can I use this as a table later, meaning naming it something then using its rows and columns in other queries?
I can't solve this problem for the life of me. I'm a beginner. It's just one table but I just can't get a query working. Here is what I have:
Hotel table and Room table (I'll just need to use the Room table; I mentioned Hotel just as a reference point for understanding).
Room has the following columns: (Number,HID) - this is a composite primary key; Number is the numerical number of the room and HID is the ID of the hotel which it belongs to. I also have one more column, Name. Now the problem is:
Find all the Hotels which only have rooms Named OneBedroom
I tried (and failed) by doing it by selecting all HIDs from Room, then filtering on not exist(hotels that have at least one non-OneBedroom named room), but I couldn't make this work.
Room
Number HID Name
1 H1 OneBedroom
2 H2 OneBedroom
3 H1 OneBedroom
4 H1 OneBedroom
5 H2 TwoBedroom
6 H3 OneBedroom
Desired Output: HID
H1
H3
I suspect something like this would do it
SELECT DISTINCT `hid` FROM `room` WHERE
`room`.`hid` NOT IN
(SELECT `hid` as `hid` FROM `room` WHERE `name` != "OneBedroom");
Untested, might be crap, but seems like it should work. Basically, the inner query gets all hid's of rooms that are not OneBedrooms. We then subtract all of those hid's from a full list of hid's.
The easiest way is using group by plus having with a conditional count, so no need to include aditional subquery.
This return hotel with all room = "OneBedroom", remember COUNT only count values <> NNLL
SELECT `hid`
FROM `room`
GROUP BY `hid`
HAVING COUNT(CASE WHEN `name` != "OneBedroom" THEN 1 END ) = 0
At least one bedroom is call "OneBedroom"`
HAVING COUNT(CASE WHEN `name` = "OneBedroom" THEN 1 END ) >= 1
The default value for CASE is NULL so no need for ELSE part
I'm going with a table like this from what you describe:
table Room
HID Number Name
----------------------------------------
1 101 OneBedroom
1 102 OneBedroom
1 103 TwoBedroom
1 201 Suite
2 101 OneBedroom
2 102 OneBedroom
2 103 OneBedroom
which I assume connects to a table Hotel:
table Hotel
HID name
------------------
1 StayOver
2 SleepTite
Now for the query:
SELECT h.name
FROM Hotel h
WHERE h.HID NOT IN (SELECT r.HID
FROM Room r
WHERE name != 'OneBedroom');
which will give you a list of the hotel names with only one bedroom rooms.
Works on SQLite with sample data. Should be okay.
EDIT - based on edited question:
SELECT h.HID . . .
instead of h.name in above query.

Sql Query to get number of floors

I am working on a hotel management software and I need to display floors and the rooms on that floor......
I have a wing_master table in the database with following columns -:
wing_id,
wing_name,
floor,
floor_room_count,
status
Its like I have a record for one wing in that hotel which has 4 floors, but when I write a query to get the floors in that wing it just gives me "4" as the result in sql.....
I want the query to return it as follows -:
1
2
3
4
I want it this way so that I can use nested data-list control in asp.net....
My query is "select floors from wing_master where wing_id = 1"
For most databases (not MySQL), you can use a recursive query to obtain all floors:
with all_floors as (
select floors from wing_master where wing_id = 1
union all
select floors - 1 as floors from all_floors
where floors > 1
)
select * from all_floors order by floors;
SQLFiddle example.
In MySQL, the easiest way would be to create a numbers table that has a sequence of numbers up to the highest possible floor. Then join to that table to get all floors:
select num from wing_master
join numbers on
wing_id = 1 and
num <= floors;
SqlFiddle example.
Your query is ok, and also it seems that query and table structure will be fulfilling your requirements. can you show your data, because as per the structure, there should be four rows in the table, showing floor 1, 2, 3, 4
something like this
floor wing_id
1 1
2 1
3 1
4 1
If that is how your data looks, then your query must be ok, else there is some other issue. so do share your structure with few rows of data.