SQL Query question - database

No particular DBMS in mind, how would I do the following:
# There are many tables per one restaurant, many napkins per one table
# Pseudo SQL
SELECT RESTAURANT WHERE ID = X;
SELECT ALL TABLES WHERE RESTAURANT_ID = RESTAURANT.ID;
SELECT ALL NAPKINS WHERE TABLE_ID = TABLE.ID;
But, all in one query? I've used a JOIN to get all the tables in the same query as restaurant, but is it possible to get all napkins for each table as well, in the same query?

select * -- replace * with the columns you need...
from restaurant as r
inner join tables as t on t.restaurant_id = r.id
inner join napkins as n on n.table_id = t.id
where r.id = [restaurant id]

You would definitely end up in repeating Tables and restaurant information on the rows, like:
Restaurant1 Table1 Napkin1
Restaurant1 Table1 Napkin2
Restaurant1 Table1 Napkin3
Restaurant1 Table2 Napkin4
Restaurant2 Table1 Napkin5

It seems you want to return three separate results, not a single result with repeat values for RESTAURANT_N or TABLE_N.
In SQL, this is done with stored procedures which can return multiple result sets. The syntax for stored procedures varies among database products, therefore you should ask the question for specific products. In the stored procedure, there will be three select statements for the RESTAURANTS, TABLES and NAPKINS. The results of the three statements are returned in a bundle to the application, which can then use the results.

Related

SQL Joining journal tables to user tables

I have a MSSQL database with 3 tables: Journals, Customers, and UserAccounts.
I'm trying to query Journals for transactions per account manager. This table has a customer ID column that links to Customers.
The Customers table has a ACC_Manager column that links to UserAccounts via UserID.
Inside the UserAcounts table are first and last name columns.
So it would be
Select
Journal.amount,
Customer.name,
UserAccounts.first
From
Tables
where
Journal.ACC_manager = 'Matt'
I'm having issues joining the tables so I can query using UserAccounts.first. Could anybody help? Thanks
Try the following. I didn't get exact column names so don't just use this code without modifying it a bit to suit your specific needs:
SELECT
j.amount,
c.name,
u.first
FROM
Journals j
JOIN Customers c ON
c.customerID = j.customerID -- Exact column names?
JOIN UserAccounts u ON
u.UserID = c.ACC_Manager
WHERE
u.first = 'Matt'
You may also need to use LEFT JOIN as opposed to JOIN. Read up on JOINs to be sure.

Need query to determine number of attachments for each issue

I have a database in SQL Server that has three tables: Issues, Attachments, and Requestors. I need a single query that returns all the columns contained in the "Issues" and "Attachments" tables. Listed below is the query that I've created, but it's not working as expected:
SELECT A.*,
B.*,
SubQuery.attachmentcount
FROM [DB].[dbo].[issues] AS A
FULL OUTER JOIN [DB].[dbo].[requestors] AS B
ON A.issue_id = B.issue_id,
(SELECT Count(attachments.attachment_id) AS AttachmentCount
FROM issues
LEFT OUTER JOIN attachments
ON issues.issue_id = attachments.issue_id
WHERE attachments.attachment_status = 1
GROUP BY issues.issue_id) AS SubQuery;
Pictures describing the three tables are listed below:
Any ideas on how to fix my query?
Thanks,
"I need a single query that returns all the columns contained in the "Issues" and "Attachments" tables".
Based on this sentence try this:
SELECT A.Issue_ID, I.Issue_Name,r.Name, COUNT(A.attachment_id) AS Count
FROM Attachments as A
INNER JOIN Issues I on I.issue_id = A.issue_id
INNER JOIN requestors as R on A.issue_id = R.requestor_id
WHERE A.attachment_status = 1
GROUP BY A.Issue_ID, I.Issue_Name, r.Name
--Specify all columns by name (don't use *)
Keep It Simple and Try This!
SELECT i.Issue_ID, i.Issue_Name, COUNT(a.attachment_id) AS AttachmentCount
FROM attachments a JOIN
issues i ON
i.issue_id = a.issue_id
WHERE a.attachment_status = 1
GROUP BY i.Issue_ID, i.Issue_Name
Add your Desired Columns in Both Select List and Group By Clause and you are done.

How to compare the results of two separate queries that have a common field in Sql Server?

Maybe it's because it's Friday but I can't seem to get this and it feels like it should be really really easy.
I have one result set (pulls the data from multiple tables) that gives me the following result set:
Room Type | ImageID | Date
The next query (pulled from separate tables than above) result give me :
ImageID | Date | Tagged
I just want to compare the results to see which imageid's are common between the two results, and which fall into each list separately.
I have tried insert the results from each into temp tables and do a join on imageid but sql server does NOT like that. Ideally I would like a solution that allows me to do this without creating temp tables.
I researched using union but it seems that because the two results don't have the same columns I avoided that route.
Thanks!
You can do this a number of different ways, for instance you can use either a inner join or intersect using the two sets as derived tables.
select ImageID from (your_first_query)
intersect
select ImageID from (your_second_query)
or
select query1.ImageID
from (your_first_query) query1
inner join (your_second_query) query2 on query1.ImageID = query2.ImageID
You don't explain why SQL-Server does not like performing a join on ImageId. Shouldn't be a problem. As to your first question, you need to transform your two queries into subqueries and perform a Full Out Join on them:
Select * from
(Select Room Type, ImageID, Date ...) T1 Full Outer Join
(Select ImageID, Date, Tagged ...) T2 on T1.ImageId = T2.ImageId
The analysis of Null values on both side of the join should give you what you want.
SELECT TableA.ImageID
FROM TableA
WHERE TableA.ImageID
IN (SELECT TableB.ImageID FROM TableB)
select q1.ImageID
from (your_first_query) q1
WHERE EXISTS (select 1
from (your_second_query)
WHERE ImageID = q1.ImageID)

Proper way to filter a table using values in another table in MS Access?

I have a table of transactions with some transaction IDs and Employee Numbers. I have two other tables which are basically just a column full of transactions or employees that need to be filtered out from the first.
I have been running my query like this:
SELECT * FROM TransactionMaster
Where TransactionMaster.TransID
NOT IN (SELECT TransID from BadTransactions)
AND etc...(repeat for employee numbers)
I have noticed slow performance when running these types of queries. I am wondering if there is a better way to build this query?
If you want all TransactionMaster rows which don't include a TransID match in BadTransactions, use a LEFT JOIN and ask for only those rows where BadTransactions.TransID Is Null (unmatched).
SELECT tm.*
FROM
TransactionMaster AS tm
LEFT JOIN
BadTransactions AS bt
ON tm.TransID = bt.TransID
WHERE bt.TransID Is Null;
That query should be relatively fast with TransID indexed.
If you have Access available, create a new query using the "unmatched query wizard". It will guide you through the steps to create a similar query.

TSQL query to merge data from multiple tables that may or may not have matching rows?

For example, suppose we're conducting research where students can take up to 10 different tests, and each table in the database stores all the students' responses for one test. The tables are named after each test as: T1, T2, ... , T10. Suppose each table has a primary key column 'Username' that identifies each student. Students may or may not have completed each test, so there may or may not be a record in each table for each student.
What is the correct SQL Query to return all the test data from all tables, with one row per student (one row per username)? I want the simplest query possible that returns the correct results. I would also like to coalesce the Username fields into a single Username field in the final query.
To clarify, I understand that SQL has a major limitation in that it does not support a syntax to select all columns except one or more fields like "select *[^ExcludeColumn1][^ExcludeColumn2]". To avoid specifically naming all columns in the final query, it would be acceptable to leave all the Username columns there, as long as it includes a coalesced Username field at the beginning named something like RowID.
As for the overall query, one option would be to perform a union all on the username column of all ten tables, then select the distinct usernames across all tables, then perform a series of left joins against the list of distinct usernames on all 10 tables. That would result in a very straightforward query where each left join is performed on the same distinct set of usernames, but I want to avoid a separate up-front query for distinct usernames. (Although if that's the best option, let me know). It would look something like this:
select * from
(select distinct coalesce(t1.Username,t2.Username,...,t10.Username) as RowID from t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) distinct_usernames
left join t1 on t1.Username = distinct_usernames.RowID
left join t2 on t2.Username = distinct_usernames.RowID
...
left join t10 on t10.Username = distinct_usernames.RowID
Although that is short and easy to write, it is incredibly inefficient and would take hours to run on test tables with 5000+ rows each, so with an adjustment, an equivalent version that runs in a few seconds is:
select * from (
select distinct Username as RowID from (
select Username from t1
union all
select Username from t2
union all
...
select Username from t10
) all_usernames) distinct_usernames
left join t1 on t1.Username = distinct_usernames.RowID
left join t2 on t2.Username = distinct_usernames.RowID
...
left join t10 on t10.Username = distinct_usernames.RowID
I think that what I have above might be the most efficient and correct query (takes only a couple seconds to run and returns correct result set), but I also thought perhaps it could be simplified with some kind of full join. The problem is that full joins get confusing with more than two tables, because without pre-determining the usernames, each subsequent table would have to match records against any of the preceding tables, resulting in a query where each additional table has "[previous table count] + 1" conditions on matching the username.
Assuming that Username is unique in each table, your second query would be the way I would try first, with the slight modifications of removing distinct and simply using union (which implies distinct) rather than union all:
select *
from (
select Username from t1
union
select Username from t2
union
-- ...
select Username from t10
) distinct_usernames
left join t1 on t1.Username = distinct_usernames.Username
left join t2 on t2.Username = distinct_usernames.Username
-- ...
left join t10 on t10.Username = distinct_usernames.Username
From there I would make sure that Username is indexed, possibly even using it as the clustered index. I've also had optimization luck in the past by implementing your distinct_usernames as a temp table (possibly indexed, or an indexed view) at the beginning of the proc, but only testing would determine if that were worthwhile.
A full outer join would require a bunch of or conditions or coalesce arguments, though it could be worth a try on just a few tables to see if the performance is there. I can't try to out-guess what your query engine will like best.
Also, getting just the column names that you want could be done with a query to sys.columns or information_schema.columns and using dynamic SQL to build your query as a string and then executing that.

Resources