I have the following table structure of my database:
db structure
My aim is to output every row of tbl_Therapeuten (these are my employees) with the name of their trainings (in german "Fortbildung").
The names of the trainings are stored in tbl_Forbildungen. And the trainings which each employee has is stores in tbl_Therapeut_Fortbildung. For the output I want to show the name of the training, not the id.
Like this:
output
I am programming in C#, SQL Server.
First I tried this:
string sSQL = "SELECT t.*, STRING_AGG(tf.Id_Fortbildung, ';') AS Fortbildungen " +
"FROM tbl_Therapeuten t " +
"FULL OUTER JOIN tbl_Therapeut_Fortbildung tf on t.Id = tf.Id_Therapeut ";
But this brings an error containing that I don't use tbl_Therapeuten.Id in an aggregate function or in a Group by clause.
Next I tried this:
string sSQL = "SELECT t.Id, t.Nachname, STRING_AGG(tf.Id_Fortbildung, ';') AS Fortbildungen " +
"FROM tbl_Therapeuten t " +
"FULL OUTER JOIN tbl_Therapeut_Fortbildung tf on t.Id = tf.Id_Therapeut " +
"GROUP BY t.Id, t.Nachname";
This worked (except displaying the name of the training but the Id) but I don't want to explicitly name every column of tbl_Therapeuten. I want to use "t.*". But this is not working:
string sSQL = "SELECT t.*, STRING_AGG(tf.Id_Fortbildung, ';') AS Fortbildungen " +
"FROM tbl_Therapeuten t " +
"FULL OUTER JOIN tbl_Therapeut_Fortbildung tf on t.Id = tf.Id_Therapeut " +
"GROUP BY t.*";
So I need some help :)
And what I also don't know how to do is to display the name of the trainings instead of the id.
Thanks for your help!
You might find that a correlated subquery provides better performance (by avoiding the outer aggregation) and allows you to avoid listing all columns from t:
SELECT T.*,
(SELECT STRING_AGG(F.Name, ';')
FROM tbl_Therapeut_FortBildung TF JOIN
tbl_FortBildungen F
ON F.Id = TF.Id_FortBildung
WHERE TF.Id_Therapeut = T.Id
) as Fortbildungen
FROM Therapeuten T
I think this is what you need.
SELECT T.Id,T.Name,T.Street,T.BirthDate,STRING_AGG(F.Name,';')
FROM Therapeuten T
LEFT JOIN tbl_Therapeut_FortBildung TF ON TF.Id_Therapeut=T.Id
LEFT JOIN tbl_FortBildungen F ON F.Id=TF.Id_FortBildung
GROUP BY T.Id,T.Name,T.Street,T.BirthDate
As far as I know SQL server does not support the GROUP BY *, so you will have to specify the column names.
Related
on the internet i find only very few info about count in ms access
there is query string
"SELECT students.Student FROM specialty INNER JOIN (groups INNER JOIN
((mark INNER JOIN students ON mark.idstudent = students.IDstudent)
INNER JOIN miss ON students.IDstudent = miss.IDstudent)
ON(groups.IDgroup = students.IDgroup) AND(groups.IDgroup = miss.IDgroup))
ON specialty.IDspecialty = groups.IDspecialty WHERE specialty.Name =
'" + DateFind.otdel + "' GROUP BY students.Student"
what does it - it selects all students with misses, 2, non-admission to lessons. And i need to count amount of students with that parameters.
and i tried to do something with counting via adding
SELECT COUNT(student) FROM students.student WHERE
and it does nothing. Idk how to work with count so help pls, i rly checked on internet and there was only simple queries like count by 1 field without any innerjoins and etc.
If your posted query works, then wrap this as a subquery:
"Select Count(*) From (SELECT students.Student FROM specialty INNER JOIN (groups INNER JOIN
((mark INNER JOIN students ON mark.idstudent = students.IDstudent)
INNER JOIN miss ON students.IDstudent = miss.IDstudent)
ON (groups.IDgroup = students.IDgroup) AND (groups.IDgroup = miss.IDgroup))
ON specialty.IDspecialty = groups.IDspecialty WHERE specialty.Name =
'" + DateFind.otdel + "' GROUP BY students.Student) As T"
I have a problem with SQL query in C#.
In my database I have tables: Supplier, ApplicationForm, SupplierAdress. I was trying to join these three tables but I got an syntax error with the inner join.
Also my method in C# have input parameter AppFormID. With that parameter I have to open particular Application Form from database on Windows app.
This is my SQL query:
command.CommandText = "select ApplicationForm.Date,ApplicationForm.About,ApplicationForm.Supplier," +
" Supplier.IDSupplier,Supplier.Name,Supplier.Email,Supplier.Phone," +
" Supplier.SupplierAdress,SupplierAdress.AdressID,SupplierAdress.Name" +
" from ApplicationForm" +
" inner join Supplier on ApplicationForm.Supplier=Supplier.IDSupplier" +
" inner join SupplierAdress on ApplicationForm.Supplier.SupplierAdress = SupplierAdress .AdressID" +
" where ApplicationForm.ApplicatonFormID=" + AppFormID;
I hope that someone will help me.
This is wrong ApplicationForm.Supplier.SupplierAdress
try this, dunno exact field names:
from
ApplicationForm
inner join Supplier on ApplicationForm.Supplier=Supplier.IDSupplier
inner join SupplierAdress on Supplier.IdAdress =SupplierAdress.AdressID
I am running a sql query using two tables namely QuestionInsert and Question_Papers.
The columns in th erespective table are as follows:-
Table:-QuestionInsert
Columns:-QuestionNum,Question,Answer,CatId,SubCatId
Table:-Question_Papers
Columns:-QuestionNum
I want an sql query which will retrieve all QuestionNum,Question,Answer from table QuestionInsert which QuestionNum is present in table Question_Papers.
Also, I want to retrieve all QuestionNum,Question,Answer from table QuestionInsert which QuestionNum is not present in table Question_Papers.
This data is displayed on a Grid View.The queries I am using are as follows:-
The Query for first condition is:
SELECT F.QuestionNum,
F.Question,
F.Answer
FROM QuestionInsert F
INNER JOIN Question_Papers FS ON F.[QuestionNum]=FS.QuestionNum
WHERE ((F.QuestionNum=FS.QuestionNum) AND (F.CatId='" +
DropDownList1.SelectedValue + "' And F.SubCatId='" + DropDownList3.SelectedValue + "'))
ORDER BY F.QuestionNum DESC;
The other query for 2nd condition. is:-
SELECT F.QuestionNum,
F.Question,
F.Answer
FROM QuestionInsert F INNER JOIN Question_Papers FS ON F.[QuestionNum]!=FS.QuestionNum
WHERE ((F.QuestionNum!=FS.QuestionNum) AND (F.CatId='" + DropDownList1.SelectedValue + "'
And F.SubCatId='" + DropDownList3.SelectedValue + "'))
ORDER BY F.QuestionNum DESC
My code is retrieving correct information but if more than one row of same QuestionNum is present in Question_Papers table, it is displaying all the rows repeatedly. I want to display the unique rows which are present and not present in table Question_Papers separately.
Kindly help me.
You could try the following for the second condition:
SELECT F.QuestionNum,F.Question,F.Answer
FROM QuestionInsert F
WHERE (F.CatId='" + DropDownList1.SelectedValue + "' And F.SubCatId='" + DropDownList3.SelectedValue + "')
AND F.QuestionNum NOT IN (SELECT QuestionNum FROM Question_Papers)
ORDER BY F.QuestionNum DESC
And this for the first condition:
SELECT F.QuestionNum,F.Question,F.Answer
FROM QuestionInsert F
WHERE (F.CatId='" + DropDownList1.SelectedValue + "'
AND F.SubCatId='" + DropDownList3.SelectedValue + "')
AND F.QuestionNum IN (SELECT QuestionNum FROM Question_Papers)
ORDER BY F.QuestionNum DESC";
However, there are serious problems with your code - have you looked into SQL injection? There are many data access frameworks, like Entity Framework, that would push you down a better route.
Your first query can be rewritten using EXISTS
SELECT F.QuestionNum,F.Question,F.Answer FROM QuestionInsert F
WHERE EXISTS (SELECT * FROM Question_Papers P WHERE P.QuestionNum = F.QuestionNum)
AND F.CatId='" + DropDownList1.SelectedValue + "'
AND F.SubCatId='" + DropDownList3.SelectedValue + "'
Second query using NOT EXISTS
SELECT F.QuestionNum,F.Question,F.Answer FROM QuestionInsert F
WHERE NOT EXISTS (SELECT * FROM Question_Papers P WHERE P.QuestionNum = F.QuestionNum)
AND F.CatId='" + DropDownList1.SelectedValue + "'
AND F.SubCatId='" + DropDownList3.SelectedValue + "'
Please note that with the way those queries are written (which was taken from your question), you are vulnerable to SQL Injection. You should use parameters instead.
There doesn't appear to be a need to use a join nor a reason for repeating the join clause within where. Form what I can gather all you need to do is check for existence, which recent versions (2005+) of sql server supports with EXISTS. Doing this as a single query than a correlated subquery can be used to check and flag existence
DECLARE #question_insert TABLE ( id INT, question VARCHAR(50), answer VARCHAR(50), catid INT, subcatid INT )
DECLARE #question_paper TABLE ( id INT, question_insert_id INT )
INSERT INTO #question_insert ( id, question, answer, catid, subcatid )
VALUES
(1, 'How old are you?', '20', 1, 1),
(2, 'Who was the first president?', '?', 2, 1)
INSERT INTO #question_paper ( id, question_insert_id )
VALUES (1, 1),(2, 1)
SELECT
qi.id,
qi.question,
qi.answer,
CASE WHEN EXISTS(SELECT 1 FROM #question_paper qp
WHERE qp.question_insert_id = qi.id)
THEN 'Yes' ELSE 'No' END AS in_question_paper
FROM #question_insert qi
--WHERE qi.catid=#catid AND qi.subcatid=#subcatid
demo
Alternatively AS individual queries
SELECT
qi.id,
qi.question,
qi.answer,
'Yes' AS in_question_paper
FROM #question_insert qi
WHERE EXISTS(SELECT 1 FROM #question_paper qp
WHERE qp.question_insert_id = qi.id)
And
SELECT
qi.id,
qi.question,
qi.answer,
'No' AS in_question_paper
FROM #question_insert qi
WHERE NOT EXISTS(SELECT 1 FROM #question_paper qp
WHERE qp.question_insert_id = qi.id)
I will reiterate that you should read up on SQL Injection and not concatenate user input into queries.
Also re. DISTINCT not being "acceptable in joins" that is not the case. What is not acceptable is to use DISTINCT and refer to a column that is not part of select list in another part of the query (in this case it would've been the WHERE clause), a way round this is to use GROUP BY instead.
So I'm retrieving data from the database using odbc. One of my fields, which was causing the problem, is AutoNumber. In my query when I use, '" convert.toint64(empid)"', I get an error of data type missmatch. But when I used parameter, it worked perfectly. Can someone tell me what is the difference. As far as I know, AutoNumber is a long integer and long int is 64, right?
here are both of my queries:
string cmdText = "SELECT p.projID, p.projName, a.wageperday " +
"FROM ((projects p INNER JOIN assigns a ON p.projID = a.projname) " +
"INNER JOIN empos e ON a.employeeID= e.ID) " +
"WHERE a.employeeID = ?";
OdbcCommand assignslist = new OdbcCommand(cmdText, _connection);
assignslist.Parameters.AddWithValue("#empID", empid);
OdbcDataReader readassigns = assignslist.ExecuteReader();
GridView1.DataSource = readassigns;
GridView1.DataBind();
(this one works fine)
string cmdText = "SELECT p.projID, p.projName, a.wageperday " +
"FROM ((projects p INNER JOIN assigns a ON p.projID = a.projname) " +
"INNER JOIN empos e ON a.employeeID= e.ID) " +
"WHERE a.employeeID = '" + convert.toint64( empid ) + "';
OdbcCommand assignslist = new OdbcCommand(cmdText, _connection);
OdbcDataReader readassigns = assignslist.ExecuteReader();
GridView1.DataSource = readassigns;
GridView1.DataBind();
for this one, i get an error even if I removed the conversion, I get an error.
One more question, I don't understand INNER JOIN perfectly and the above code was from a user here who helped me. I don't understand why did he use "FROM ((projects p INNER JOIN assigns a ON p.projID = a.projname) " +
"INNER JOIN empos e ON a.employeeID= e.ID)"
two brackets -- I mean a bracket inside a bracket. And if I wanna join a 4th or 5th table do I have to put it inside a bracket aside from the main bracket? An example would be much appreciated!
If a.employeeID is a number then your problem are the quotes and the concatenation of a number to a string.
"WHERE a.employeeID = " + convert.toint64(empid).ToString()
but this make no sense because you have a string to build so, you could simply write
"WHERE a.employeeID = " + empid.ToString();
however use always the parameterized query. That is the correct way to go.
A parameterized query allows the Framework code to pass the parameters with the correct format and you don't have to worry about quoting values, format of dates and decimal separators. (And last but not least, you avoid any possibilities of Sql Injection)
For the second part of your question, JOIN is used to put togheter data from two tables, when you have more than one JOIN the parenthesys help to understand how the grouping from the tables are perfomed. First the data from projects and assigns are grouped together following the rules of the INNER JOIN then the resulting set of data is joined with the data from the employee table following the rules of the second join.
In your second query, instead of using convert.toint64( empid ) try using empid.ToString():
"WHERE a.employeeID = " + empid.ToString();
The error you were receiving was due to the fact that you were trying to concatenate a string with an integer.
With regards to the INNER JOINs you are using, the use of the brackets is dependant upon the database you are using. In most cases, you will not need the brackets at all and they can be removed without any issue, so you could rewrite the query to:
string cmdText = "SELECT p.projID, p.projName, a.wageperday " +
"FROM projects p " +
"INNER JOIN assigns a ON p.projID = a.projname " +
"INNER JOIN empos e ON a.employeeID = e.ID " +
"WHERE a.employeeID = " empid.ToString();
You're trying to add a string and an integer, which isn't allowed automatically. You'd have to convert the number to a string first, like this:
"WHERE a.employeeID = '" + empid.ToString() + "';
But, using parameters is the better way for other reasons (best habit to be in, to avoid SQL-injection attacks, etc.).
So i learned how to do a bulk insert using data from one table as the userId from another table. Now i tried to do the same thing but i have a SQL(ite) error. I took a guess at the syntax and i got it wrong. After i bulk insert into the subscription i want to add 1 to each of the users media count. I have a left join error. How do i correct it?
-edit- I haven't solve this yet. Please help.
NOTE: I am using sqlite ATM but I am switching to mysql or MS sql
void updateMediaForSubscribers(long userId, long mediaId, Media_Base.Catagory cat, DateTime currentDate)
{
command.CommandText =
"INSERT INTO user_media_subscription (recipientId, mediaId, catagory) " +
"SELECT watcher, #mediaId, #category " +
"FROM user_watch WHERE watched=#watched;";
command.Parameters.Add("#mediaId", DbType.Int64).Value = mediaId;
command.Parameters.Add("#category", DbType.Int64).Value = cat;
command.Parameters.Add("#watched", DbType.Int64).Value = userId;
command.ExecuteNonQuery();
//near "LEFT": syntax error
command.CommandText =
"UPDATE user_data SET mediaMsgCount=mediaMsgCount+1 " +
"LEFT JOIN user_watch AS w ON w.watcher=user_data.userId " +
"WHERE w.watched=#watched;";
command.Parameters.Add("#watched", DbType.Int64).Value = userId;
command.ExecuteNonQuery();
}
UPDATE user_data
SET mediaMsgCount=mediaMsgCount+1
LEFT JOIN user_watch AS w ON w.watcher=user_data.userId
WHERE w.watched=#watched
Looks like it won't work to me, because you're joining in an UPDATE query but without a "FROM" clause, have you tried:
UPDATE u
SET u.mediaMsgCount = u.mediaMsgCount+1
FROM user_data u
LEFT JOIN user_watch AS w ON w.watcher=u.userId
WHERE w.watched=#watched
UPDATE user_data
SET mediaMsgCount = u.mediaMsgCount + 1
FROM user_data u LEFT OUTER JOIN user_watch w ON w.watcher = u.userId
WHERE w.watched=#watched
Honestly, I'm not really sure why you're using a left outer join since the update is dependant on user_watch... might want to change the "LEFT OUTER JOIN" to an "INNER JOIN".
Also, its a good idea to prefix your table name with the owner, I.E. dbo.user_data ... if you dont do that then sql server has to do a lookup.