Final Query Table - What the final table should look like.
Pubs Tables - I did not include the author_id which needs to be changed to SSN.
I am very new to this - like three weeks into this class. I'm struggling to wrap my brain around the concepts but it looks like there is a wealth of information on stack overflow I need to keep reading....it would help if I were actually using a database on a regular basis in a real life situation right now. Here is my query I keep coming up with an error on - possible I am making beginner mistakes I'm not seeing or understanding. I want to understand and get this down before it gets harder.
USE pubs
SELECT DISTINCT authors_id as SSN
FROM authors
SELECT au_lname, au_fname as fullname
FROM authors
INNER JOIN author
WHERE royalsched = <50
I'm getting an error message - incorrect syntax near the word where, msg 156, level 15 state 1 line 7
The question is: Select the unique author id as ssn, the lastname and firstname separated by a comma (smith, joe) as Fullname from the authors table joined on the titleauthor table where the royaltyper is less than 50. Order the query by the fullname. I get that I need to append the values of the fields together (concatenate) by using the + symbol and I know that I need to join them - just not sure if I'm headed in the right direction or not. Is there a place you can check your queries like validator online (to show where you've missed stuff?)
Update 10/6/16:
Tried it again. This is my reasoning: join the tables (INNERJOIN?) bring together the first name and last name (field 1 + field 2) althoughthis is where you were saying I need to do something different. This is what I came up with but it is not working: (authors_id is what it is called in the database so it needs to be changed to SSN, au_lname and au_fname need to be combined into one column as FullName) then it needs to show the royaltyper is less than 50.
SELECT authors_id = SSN FROM authors AS INNER JOIN ON au_lname + au_fname WHERE royaltyper = <50
Your join is missing an ON clause to tell how authors and (title?)author are related. For instance, ON authors.id=titleauthor.author_id.
That's what it is expecting where it sees WHERE. (mysql also supports a USING () syntax instead of ON. But one or the other must be specified for non-CROSS joins.)
To concatenate in mysql, you use CONCAT, not +. E.g.:
concat(au_lname,', ',au_fname) as Fullname
Related
I am asking this question which is to teach myself of using correct approach in a certain scenario than any how-to-code problem.
Since I am self taught student and haven't used relational tables before. With search and experiment, I have come to know the basic concept of relations and their usage but I am not sure if I am still using the correct approach while using these tables.
I do not have any official teachers so only place I can ask troubling questions is here with you guys.
For example, I have written a little code where I have 2 tables.
Table-1 is doctors which has an id (AI & Primary) and names table of varChar.
Table-2 is patient_recipts which has a doctor_name table of tinyInt
names table hold the name of the doctor
doctor_name table holds the corresponding id from doctors table
name and doctor_name are related to each other in database
Now when I need to fetch data from patient_recipts and display doctor's name, I will need to INNER JOIN doctor table, compare the doctor_name value with id in doctor table and get the name of the doctor.
The query I will use to fetch patients of a certain doctor, is something like,
$getPatList = $db->prepare("SELECT *
FROM patient_recipts
INNER JOIN doctor ON patient_recipts.doctor_name = doctor.id
WHERE dept = 'OPD' AND date_time = DATE(NOW())
ORDER BY patient_recipts.id DESC");
Now if I were to INSERT an action log entry in some other processor file, it would be something like (action and log entry),
$recipt_no = $_POST['recipt_no'];
$doctor_name = $_POST['doctor_name']; //this hold id(int) not text
$dept = $_POST['dept'];
$patient_name = $_POST['patient_name'];
$patient_tel = $_POST['patient_telephone'];
$patient_addr = $_POST['patient_address'];
$patient_age = $_POST['patient_age'];
$patient_gender = $_POST['patient_gender'];
$patient_fee = $_POST['patient_fee'];
$logged_user = $_SESSION['user_name'];
$insData = $db->prepare("
INSERT INTO patient_recipts (date_time, recipt_no, doctor_name, dept, pat_gender, pat_name, pat_tel, pat_address, pat_age, pat_fee, booked_by)
VALUES (NOW(),?,?,?,?,?,?,?,?,?,?)");
$insData->bindValue(1,$recipt_no);
$insData->bindValue(2,$doctor_name);
$insData->bindValue(3,$dept);
$insData->bindValue(4,$patient_gender);
$insData->bindValue(5,$patient_name);
$insData->bindValue(6,$patient_tel);
$insData->bindValue(7,$patient_addr);
$insData->bindValue(8,$patient_age);
$insData->bindValue(9,$patient_fee);
$insData->bindValue(10,$logged_user);
$insData->execute();
// Add Log
write_log("{$logged_user} booked OPD of patient {$patient_name} for {$doctor_name}");
OUTPUT: Ayesha booked OPD of patient Steve for 15
Now here the problem is apparent, I would need to execute the above mentioned fetch query yet again to get name of the doctor with ID comparison and bind the ID 15 to Doctor's name before calling the write_log() function.
So this is where I think my approach has been wrong altogether.
One way could be using actual doctor name in patient_recipts rather than ID
but this would i, in first place, kill the purpose of learning related tables and keys, learning design scenarios and troubleshooting.
Please help so I can understand and implement a better approach for days to come :)
Your table structure is correct, it's considered best practice to use the ID as the foreign key in other tables. If you want to include the doctor's name in the log message, you do have to do another SELECT query. A query like
SELECT name
FROM doctor
WHERE id = :doctor_id
is not very expensive.
But you can simply live with the log file only containing IDs. Look up the doctor's name later if you need to find out which doctor a particular log message is referring to.
BTW, when you use PDO, I recommend you use named placeholders (as in my example above) rather than ?. It makes the code easier to read, and if you modify the query to add or remove columns you don't have to change all the placeholder numbers.
Okay, let's say I have a table called rooms:
It only has one column: ID
I also have another table called items_in_rooms with columns:
roomId, itemName, itemColor
Whenever a room-record is inserted a bunch of records is also inserted into items_in_rooms linked to the row-record, specifying what items are in that room.
The problem is that when a room-record along with its items, I need to first verify if a room with those exact items don't already exist.
How can this be done?
One way of course would be to first fetch all room-records along with all their items then look through them until it has been verified there isn't already an exact copy in the database and then do insertion if it's unique.
But this sounds a bit ineffective to me, especially as the tables grows very large so I was hoping there's a way to have MYSQL do the checking.
One way I came up with was to do something like this:
SELECT roomId FROM(
SELECT rooms.id roomId, GROUP_CONCAT(
CONCAT_WS(',',itemName,itemColor) ORDER BY itemName,itemColor SEPARATOR '/'
) roomContents
FROM items_in_rooms
JOIN rooms ON roomId=rooms.id
WHERE snapshotDate='$dateString'
GROUP BY roomId
) concatenatedRoomContents
WHERE roomContents='bed,white/carpet,red/chair,brown'
Essentially this will make MYSQL concatenate each room into a string, then compare them to the "input-string" in the WHERE-clause. Obviously the input-string would have to be ordered the same way as how MYSQL orders the rows before concatenating (itemName,itemColor).
While this worked for be it felt very dirty. Also, it initially caused some problems when I had added a decimal-field as MYSQL always includes every decimal-digit when stringifying so 1 for instance could be "1.000"
while PHP which I'm using by default stringifies it to "1". I solved this using number_format() making it include the right amount of decimal-digits.
Now I've noticed I've got some duplicates in the table again so there's some other gotcha I need to find, but I was just wondering if there's maybe a more clever way?
This is how it can be done. The following query returns the id of the room if such a room exists(it has exactly those items, no more, no less).
SELECT roomId FROM (
SELECT roomId,count(*) numMatchedItems
FROM items_in_rooms WHERE (itemName,itemColor)
IN (('bed','white'),('carpet','red'),('chair','brown'))
GROUP BY roomId
) matches
WHERE numMatchedItems=3
Thanks, CBroe.
I have a query i have been working on trying to get a specific set of data, join the comments in duplicate phone numbers of said data, then join separate tables based on a common field "entry_id" which also happens to be the number on the end of the word custom_ to pull up that table.
table named list and tables containing the values i want to join is custom_entry_id (with entry_id being a field in list in which i need the values of each record to replace the words in order to pull up that specific table) i need entry_id from the beginning part of my query to stick onto the end of the word custom for every value my search returns to get the fields from that custom table designated for that record. so it will have to do some sort of loop i guess? sorry like i said I am at a loss at this point
this is where i am so far:
SELECT * ,
group_concat(comments SEPARATOR '\r\n\r\n') AS comments_combined
FROM list WHERE `status` IN ("SALEA","SALE")
GROUP BY phone_number
//entry_id is included in the * as well as status
// group concat combines the comments if numbers are same
i have also experimented on test data with doing a full outer join which doesnt really exist. i feel if you can solve the other part for me i can do the joining of the data with a query similar to this.
SELECT * FROM test
LEFT JOIN custom_sally ON test.num = custom_sally.num
UNION
SELECT * FROM test
RIGHT JOIN custom_sally ON test.num = custom_sally.num
i would like all of this to appear with every field from my list table in addition to all the fields in the custom_'entry_id' tables for each specific record. I am ok with values being null for records that have different custom fields. so if record 1 has custom fields after the join of hats and trousers and record 2 has socks and shoes i realize that socks and shoes for record 1 will be null and hats and trousers for record 2 will be null.
i am doing all this in phpmyadmin under the SQL tab.
if that is a mistake please advise as well. i am using it because ive only been working with SQl for a few months. from what i read its the rookie tool.
i might be going about this all wrong if so please advise
an example
i query list with my query i get 20,000 rows with columns like status, phone_number, comments, entry_id, name, address, so on.
now i want to join this query with custom fields in another table.
the problem is the custom tables' names are all linked to the entry_id.
so if entry_id is 777 then the custom table fields are custom_777
my database has over 100 custom tables with specials fields for each record depending on its entry_id.
when i query the records I don't know how to join the custom fields that are entry_id specific to the rest of my data.i will pull up some tables and data for a better example
this is the list table:
this is the custom_"entry_id"
Full Outer Join in MySQL
for info on full outer joins.
I'm trying to pull a list of IDs from a table Company where the first 6 characters of the ID are the same. The way our application creates a company ID is it takes the first 3 characters of the company name and the first 3 characters of the City. Beceause of that, overtime we have company IDs with the same first 6 characters, followed by a sequential number...
I was thinking using something using LIKE
Select companyID, companyName from Company Where
substring(companyID,1,6)+'%' like substring(companyID,1,6)+'%'
Basically i'm trying to get all company IDs where the first 6 characters match; The result set should show the just the top company ID ( The first 1 created) and the company name. I'm not expecting a tone of results, so i can then use the IDs returned to find the IDs below it.
I'm thinking it could maybe also be done using HAVING, where the count of IDs with the same first 6 characters are the same HAVING Count(*)>1??
Not really sure what the syntax would be...
SELECT distinct c1.CompanyID, c1.CompanyName, c2.CompanyID, c2.CompanyName
FROM dbo.Company c1
JOIN dbo.Company c2
ON SUBSTRING(c1.CompanyName,1,6) = SUBSTRING(c2.CompanyName,1,6)
AND c1.CompanyID < c2.CompanyID
order by c1.CompanyName, c2.CompanyName
SELECT c1.CompanyID, c1.CompanyName, c2.CompanyID, c2.CompanyName
FROM dbo.Company c1
INNER JOIN dbo.Company c2
ON SUBSTRING(c1.CompanyName,1,6) + '%' LIKE SUBSTRING(c2.CompanyName,1,6) + '%'
AND c1.CompanyID <> c2.CompanyID
If this is something that you envision doing frequently, I'd add a computed column to the table that has a definition of substring(CompanyName, 1, 6). You can then index it and make this efficient. As it is, it will have to scan all the entries and calculate the substring on the fly. With the computed column, you amortize the substring calculation up front and at least have a chance at an efficient query.
After trying to use Blam's script, i made a few slight changes and got some better results. His script was returning more results than rows in the table and it was pretty slow; think it's because of the company_name column. I got rid of it and wrote it like this:
select distinct c1.cmp_id, count(substring(c2.cmp_id,1,6)) as TotalCount
from company c1
join company c2 on substring(c1.cmp_id,1,6)=substring(c2.cmp_id,1,6)
group by c1.cmp_id
order by c1.cmp_id asc
This still returns all the table records, but atleast i can see the total count when the first 6 characters are listed more than once. Also, it ran in only 1 second so that's also a plus. Thank again for you input guys, always appreciated!
This is for a homework assignment. I haven't copy-pasted the question below, I made an simpler version of it that focuses on the specific area where I'm stuck.
Let's say I have a table of two values: a person's name, and the place he had lunch yesterday. Assume everyone has lunch in pairs. How can I query the database to return all the pairs of people that had lunch together yesterday? Each pair must be only listed once.
I'm actually not even sure what the professor means by return them as pairs. I've sent him an email, but no reply yet. It seems like he wants me to write a query that returns a table with column 1 as person 1 and column 2 as person 2.
Any suggestions on how to go about this? Does it seem right to assume he wants them as separate columns?
So far, I basically have:
SELECT name, restaurant FROM lunches GROUP BY restaurant, name
which essentially just reorganizes the table so that the people who had lunch together are one after the other.
We have to assume there can be only one pair eating lunch in a given restaurant.
You can get a list of pairs either using self-join:
SELECT l1.name, l2.name FROM lunches l1
JOIN lunches l2
ON l1.restaurant = l2.restaurant AND l1.name < l2.name
or using GROUP BY:
SELECT GROUP_CONCAT(name) FROM lunches
GROUP BY restaurant
The first query will return pairs in two different columns, while the second in one column, using comma as separator (default for GROUP_CONCAT, you can change it to whatever you wish).
Also note that for the first query names in pairs will come in alphabetical order as we use < instead of <> to avoid listing each pair twice.