Multiple rows in singleton select: How to make several results appear? - sql

I am currently trying to make several telephone-numbers appear in NetBeans, but it would seem the SQL query for my database is far from perfect. It always tells me: Multiple rows in singleton select.
The code allows me to get one number if it only belongs to one person, there is however one number that belongs to three people, and I need all of those three to appear. Thanks in advance!
String telephoneQuery3 = "select * from HAS_COMPETENCE where aid = (select aid from EMPLOYEE where telephone = '" + telephone + "')";

You are using = when you should use in:
select *
from HAS_COMPETENCE hc
where hc.aid in (select e.aid from EMPLOYEE e where e.telephone = '" + telephone + "')
The problem is that the subquery is returning more than one value. With =, the engine expects only one value. The in fixes this so it expects a list of values.
I also added table aliases to the query. This identifies which tables the fields are coming from -- to avoid confusion for someone looking at the query.

Comparing with = only works if the expression to its right returns one row, insetad use IN
select * from HAS_COMPETENCE where aid IN (select aid from EMPLOYEE where telephone = '" + telephone + "')";

Related

How can I identify all matching columns for two rows of data?

Using Standard ANSI SQL, how does one return a list of columns which are matching for two specific rows of data? We don't know the names of the columns, only the table name and the ID (or other primary key) to pick out the two specific rows we wish to compare?
Let's say we have a table with a large number of columns for real estate listings. If I choose two specific rows like so:
SELECT *
FROM listing_data
WHERE mls_number IN ('111111', '222222')
How can I identify the names of all other columns which happen to match between these two particular rows?
For example, perhaps there is a column called 'school_district' and they both are in the same district. Or perhaps the two listings share the same street name, or the same listing agent, or all three of these.
To get column names you can select from information_schema.columns however that is a table of column names only and does not have any data. If you are trying to do a select * from tablex where select * from tabley where columnname = 'value' then if it works at all unless your tables are small it may take hours to complete. It is simple if you know your column names to form up a query. Do some research and practice query on your tables and you should get some insight. You are unlikely to have address data in a name column so once you get familiar with your data you should be able to craft a simple query.
You need to explicitly do the comparison for each column. One method is:
SELECT (CASE WHEN ld1.col1 IS NOT DISTINCT FROM ld.col1 THEN 'col1;' ELSE '' END ||
CASE WHEN ld1.col2 IS NOT DISTINCT FROM ld.col2 THEN 'col2;' ELSE '' END ||
. . .
) as matches
FROM listing_data ld1 JOIN
listing_data ld2
ON ld1.mls_number = '111111' AND
ld2.mls_number = '222222'

Inserting Multiple Records on One Data Row SQL

I am trying to get multiple employee dependents to be on the same row of data on my output file. I can get one dependent on the employee's row, but not more than one.
I tried using a Left Join where I am joining the AutoNum so it matches with employees and dependents, but I still am only pulling one dependent.
Any ideas on how to get all needed data on one row in a SQL Access query?
SELECT E.FirstName, E.LastName, E.SSN,
Switch(E.MemberStartDate<="2018-01-01" And E.MemberEndDate>="2018-12-31","X") AS Cov12Months,
D.DepFirstName, D.DepLastName, D.ResponsibleIndividualSSN, D.CoveredIndividualSSN, D.DepDOB,
Switch(D.DepStartDate<="2018-01-01" And D.DepEndDate>="2018-12-31","X") AS DCov12Months,
FROM EMP_Test AS E LEFT JOIN Dep_Test AS D ON E.AutoNum = D.AutoNum;
Below is a sample image of what my results are currently. As you can see, Charles Soper's record is correct since he only has one dependent. But Susan Smith has two records because she has two dependents. I need both dependents on one row
A VBA method is one approach and examples provided in comment link. A CROSSTAB is also a possibility. Each approach has its pros and cons.
Consider:
TRANSFORM Max([DepFirstName] & " " & [DepLastName]) AS DepName
SELECT EmpDeps.EmpID
FROM EmpDeps
GROUP BY EmpDeps.EmpID
PIVOT DCount("*","EmpDeps","EmpID='" & [EmpID] & "' AND ID<" & [ID])+1 In (1,2,3,4,5,6,7,8,9,10);
This requires a unique identifier field in table - autonumber should serve.
Defining column names in PIVOT clause allows query to be stable enough to use as report RecordSource. This query can be joined to Employees table to retrieve additional employee info.

Is it possible to use SELECT * FROM table_name WHERE column_name = 'value' where 'value' might appear in more than one row?

I am trying to create a screen that will display the history of purchases from a particular customer. My 'Sales' table contains columns "TicketNumber", "CustomerID", "InventoryNo", "Description", "Cost", "Retail", "IndividualSubTotal", "IndividualTax", "IndividualTotal", "SaleSubTotal", "SaleTax", and "SaleTotal".
For the purposes of this screen, I will only need (for now) "TicketNumber", "CustomerID", "InventoryNo", "Retail", "IndividualTax", and "IndividualTotal".
Right now, I am trying to pull the information in by the customer's ID. My ultimate goal is to place the ticket number in the table, but I only want it to appear ONCE. I think I will be able to figure this out. But right now, this is the problem I'm having.
try {
Class.forName("org.h2.Driver");
Connection connection = DriverManager.getConnection("jdbc:h2:./RetailApplicationDatabase;AUTO_SERVER=TRUE");
String sql;
Statement stmt;
sql = "SELECT distinct TicketNumber FROM Sales WHERE CustomerID = '" + CustomerNoNumberLabel.getText() + "';";
stmt = connection.createStatement();
ResultSet results = stmt.executeQuery(sql);
DefaultTableModel model = (DefaultTableModel) TicketNumberTable.getModel();
String TicketNumber;
while(results.next()) {
TicketNumber = results.getString("TicketNumber");
model.insertRow(TicketNumberTable.getRowCount(), new Object[] {TicketNumber});
}
} catch (SQLException | ClassNotFoundException ex) {
Logger.getLogger(ViewHistoryDialog.class.getName()).log(Level.SEVERE, null, ex);
}
As you can see, while there are more results, I want to continue inserting a row into my table. CustomerID will appear in as many different item and ticket numbers that the customer has.
When I compile the program, I am not getting an errors in the output log, but I am not seeing anything being put into the table. I thought it might have been the order that I was trying to do things in, so for now, I have a button on this dialog that says "Load", and when that is pressed, the code above runs.
Where is my problem? Why am I not seeing anything being added to the table?
Thank you in advance for any helpful responses.
EDIT (01/28/2015 - 8:03 AM MST): The sale has already been added to the 'Sales' table within the database. Let's say the customer purchased inventory numbers 1, 2, and 3, and they are the first customer to make a purchase, so the ticket number is 1. Three rows are added to the 'Sales' table, for each inventory number, and the TicketNumber column will have a value of '1' in all three rows. I am then trying to retrieve this information and display it in a jTable. I want to display the ticket numbers in the jTable TicketNumberTable. But my ResultSet is not retrieving the ticket numbers.
EDIT (01/28/2015 - 8:11 AM MST): I changed the code to pull in distinct values for TicketNumber. However, this is not my primary concern, as I am still working on getting my ResultSet to retrieve information.
Your question is a little vague on inserting the ticket number only once. Does this mean for a given customer? Or for all customers? If the latter, you should enforce this as a unique constraint on TicketNumberTable.
Second, you can do the select and insert in a single statement. There is no need to run multiple queries and do looping. Something like:
INSERT INTO TicketNumberTable(TicketNumber)
SELECT distinct TicketNumber
FROM Sales
WHERE CustomerID = '. . .';
Or perhaps:
INSERT INTO TicketNumberTable(TicketNumber)
SELECT distinct TicketNumber
FROM Sales
WHERE TicketNumber NOT IN (SELECT TicketNumber FROM TicketNumberTable) AND
CustomerID = '. . .';
Wow, I determined the issue... And no one would have been able to see it... I did a SQL Query directly within the H2 console. When the table displayed, I noticed that my CustomerNo column contained a " " (space) before the number. This is because I was using a substring to extract the customer number, and the substring was off by one character, which was the space. I would have never noticed it, had I not gone deeper into it and started analyzing.
Thank you to everyone who has helped me out. Take care.

Help with Complex SQL Query

I'm still a neophyte when it comes to SQL queries, so I was hoping someone could lend me a hand.
Assume I have 3 tables, Skill, Set, and Contact, and 2 linking tables, SkillSet and ContactSet. (the 3 tables have an "ID" column that is being used as a primary key)
Contacts can have any number of sets, and vice versa (many-to-many)
Sets can have any number of skills, and vice versa (also many-to-many)
What I want is, when presented with a skill's ID, to return every contact with a set containing that skill.
Still with me?
Here's what I've got so far:
SELECT Set.ID as expr1
FROM SkillSet
WHERE Skill.ID = #SkillID
//this selects every set containing the Skill.
SELECT Contact.ID
FROM ContactSet
WHERE SET.ID = ?
//this is where I run into problems. I want to use the records returned from
//the previous SELECT query (expr1) but I'm unsure how.
//Would it be expr1.ID or expr1.Set.ID?
Thank you.
this should work just fine or at least lead you to the final solution, you only need the one query:
declare #skillid int
set #skillid = 1
SELECT C.*
FROM contact c
inner join SetContact SC on (sc.contactId = C.contactId)
inner join SkillSet SS on (ss.SetId = SC.SetId)
WHERE (SS.SkillId = #SkillId)

SQL: selective subqueries

I'm having an SQL query (MSSQLSERVER) where I add columns to the resultset using subselects:
SELECT P.name,
(select count(*) from cars C where C.type = 'sports') AS sportscars,
(select count(*) from cars C where C.type = 'family') AS familycars,
(select count(*) from cars C where C.type = 'business') AS businesscars
FROM people P
WHERE P.id = 1;
The query above is just from a test setup that's a bit nonsense, but it serves well enough as example I think. The query I'm actually working on spans a number of complex tables which only distracts from the issue at hand.
In the example above, each record in the table "people" also has three additional columns: "wantsSportscar", "wantsFamilycar" and "wantsBusinesscar". Now what I want to do is only do the subselect of each additional column if the respective "wants....." field in the people table is set to "true". In other words, I only want to do the first subselect if P.wantsSportscar is set to true for that specific person. The second and third subselects should work in a similar manner.
So the way this query should work is that it shows the name of a specific person and the number of models available for the types of cars he wants to own. It might be worth noting that my final resultset will always only contain a single record, namely that of one specific user.
It's important that if a person is not interested in a certain type of cars, that the column for that type will not be included in the final resultset. An example to be sure this is clear:
If person A wants a sportscar and a familycar, the result would include the columns "name", "sportscars" and "familycars".
If person B wants a businesscar, the result would include the columns "name" and "businesscar".
I've been trying to use various combinations with IF, CASE and EXISTS statements, but so far I've not been able to get a syntactically correct solution. Does anyone know if this is even possible? Note that the query will be stored in a Stored Procedure.
In your case, there are 8 column layouts possible and to do this, you will need 8 separate queries (or build your query dynamically).
It's not possible to change the resultset layout within a single query.
Instead, you may design your query as follows:
SELECT P.name,
CASE WHEN wantssport = 1 THEN (select count(*) from cars C where C.type = 'sports') ELSE NULL END AS sportscars,
CASE WHEN wantsfamily = 1 THEN (select count(*) from cars C where C.type = 'family') ELSE NULL END AS familycars,
CASE WHEN wantsbusiness = 1 THEN (select count(*) from cars C where C.type = 'business') ELSE NULL END AS businesscars
FROM people P
WHERE P.id = 1
which will select NULL in appropriate column if a person doesn't want it, and parse these NULL's on client side.
Note that relational model answers the queries in terms of relations.
In your case, the relation is as follows: "this person needs are satisifed with this many sport cars, this many business cars and this many family cars".
Relational model always answers this specific question with a quaternary relation.
It doesn't omit any of the relation members: instead, it just sets them to NULL which is the SQL's way to show that the member of a relation is not defined, applicable or meaningful.
I'm mostly an Oracle guy but there's a high chance the same applies. Unless I've misunderstood, what you want is not possible at that level - you will always have a static number of columns. Your query can control if the column is empty but since in the outer-most part of the query you have specified X number of columns, you are guaranteed to get X columns in your resultset.
As I said, I am unfamiliar with MS SQL Server but I'm guessing there will be some way of executing dynamic SQL, in which case you should research that since it should allow you to build a more flexible query.
You may be able to do what you want by first selecting the values as separate rows into a temp table, then doing a PIVOT on that table (turning the rows into columns).
It's important that if a person is not
interested in a certain type of cars,
that the column for that type will not
be included in the final resultset. An
example to be sure this is clear:
You will not be able to do it in plain SQL. I suggest you just make this column NULL or ZERO.
If you want the query to be dynamically expand when new cars are added, then PIVOTing could help you somewhat.
There are three fundamentals you want to learn to make this work easy. The first is data normalization, the second is GROUP BY, and the third is PIVOT.
First, data normalization. Your design of the people table is not in first normal form. The columns "wantsports", "wantfamily", "wantbusiness" are really a repeating group, although they may not look like one. If you can modify the table design, you will find it advantageous to create a third table, lets call it "peoplewant", with two key columns, personid and cartype. I can go into detail about why this design will be more flexible and powerful if you like, but I'm going to skip that for now.
On to GROUP BY. This allows you to produce a result that summarizes each group in one row of the result.
SELECT
p.name,
c.type,
c.count(*) as carcount
FROM people p,
INNER JOIN peoplewant pw ON p.id = pw.personid
INNER JOIN cars c on pw.cartype = c.type
WHERE
p.id = 1
GROUP BY
p.name,
c.type
This (untested) query gives you the result you want, except that the result has a separate row for each car type the person wants.
Finally, PIVOT. The PIVOT tool in your DBMS allows you to turn this result into a form where there is just one row for the person, and there is a separate column for each of the cartypes wanted by that person. I haven't used PIVOT myself, so I'll let somebody else edit this response to provide an example using PIVOT.
If you use the same technique to retrieve data for multiple people in one sweep, keep in mind that a column will appear for each wanted type that any person wants, and zeroes will appear in the PIVOT result for persons who do not want a car type that is in the result columns.
Just came across this post through a google search, so I realize I'm late to this party by a bit, but .. sure this really is possible to do... however, I wouldn't suggest actually doing it this way because it's usually considered a Very Bad Thing (tm).
Dynamic SQL is your answer.
Before I say how to do it, I want to preface this with, Dynamic SQL is a very dangerous thing, if you aren't sanitizing your input from the application.
So, therefore, proceed with caution:
declare #sqlToExecute nvarchar(max);
declare #includeSportsCars bit;
declare #includeFamilyCars bit;
declare #includeBusinessCars bit;
set #includeBusinessCars = 1
set #includeFamilyCars = 1
set #includeSportsCars = 1
set #sqlToExecute = 'SELECT P.name '
if #includeSportsCars = 1
set #sqlToExecute = #sqlToExecute + '(select count(*) from cars C where C.type = ''sports'') AS sportscars, ';
if #includeFamilyCars = 1
set #sqlToExecute = #sqlToExecute + '(select count(*) from cars C where C.type = ''family'') AS familycars, ';
if #includeBusinessCars = 1
set #sqlToExecute = #sqlToExecute + '(select count(*) from cars C where C.type = ''business'') AS businesscars '
set #sqlToExecute = #sqlToExecute + ' FROM people P WHERE P.id = 1;';
exec(#sqlToExecute)