1

This is kind of a weird one. This particular piece of bad database design has caught me out so many times and I've always had to make ridiculous work arounds and this is no exception. To summarize: I have 3 tables, the first one is a lookup table of questions, the second is a lookup table of answers and the third stores a questions and answer id to show which questions have been answered. So far straight forward.

However the answer can be 1 of 3 types: Free text, multiple choice or multiple selection and these are all stored in the same column (Answer). Free text can be anything, like 'Hello' or a datetime '2015-07-03 00:00:00'. Multiple choice gets stored as integers 1 or 49 etc and Multiple selection gets stored as a delimited string '1,4,7,8' (i know this is very bad design, a column shouldn't store more than 1 value however it is before my time and written into our aspx web application, as I work on my own I simply do not have the resource or time to change it)

Here comes the problem; take a look at this query:

Select *
FROM AnswersTable
JOIN LK_Questions
ON AnswersTable.QuestionID = LK_Questions.QuestionID
JOIN LK_Answers
ON AnswersTable.Answer = LK_Answers.AnswerID
Where LK_Questions.QuestionTypeID = 1

The where clause should ensure that the only questions that are returned are multiple choice. (So I am not joining a free text answer to an integer) and in fact when I run this query it runs ok but when i try to select individual columns it errors out with this error message:

Conversion failed when converting the varchar value ',879' to data type smallint.

It almost like it's doing the join before it does the where although I know the query optimizer doesn't work that way. The problem is I need to select column names as this is going into a table so I need to define the column names. ?Is there anything I can do? I've tried for ages but with no results. I should mention that I am running SQL Server 2005.

Many thanks in advance

EDIT:

This is the query that causes an error:

Select LK_Answers.Answer
FROM AnswersTable
JOIN LK_Questions
ON AnswersTable.QuestionID = LK_Questions.QuestionID
JOIN LK_Answers
ON AnswersTable.Answer = LK_Answers.AnswerID
Where LK_Questions.QuestionTypeID = 1
SQL_Kid
  • 79
  • 10
  • What table is `QuestionTypeID` part of? Also, it does work that way.. it does the `JOIN` first and then filters the rows based on conditions in the `WHERE` clause. Also, what query are you actually trying th run (with column names etc.) – Radu Gheorghiu Jul 03 '15 at 13:51
  • Im sorry its a part of the lk_questions table, ill add it in now and add the query i am rinning to the end that errors – SQL_Kid Jul 03 '15 at 13:54
  • can you post a couple rows of results just to help visualize the whole situation a little better – mgrenier Jul 03 '15 at 13:56
  • Wait, you have actual varchars and ints in the same column? Didn't know it was possible... – JSelser Jul 03 '15 at 13:57
  • I should clarify, the ints are stored as text and implicitly converted by SQL in the join – SQL_Kid Jul 03 '15 at 14:00
  • Ints stored as text is fail and now you're seeing why. Implicit conversions also makes your query run slower. You have a value that can't be implicitly converted to int, which is causing this query to fail. – Michael McGriff Jul 03 '15 at 14:05
  • 1
    In order to correct this, just explicitly cast both sides of the join to `VARCHAR` so that there is no problem matching datatypes when joining. – Michael McGriff Jul 03 '15 at 14:11
  • Michael McGriff - That worked for me. Converting in the join to varchar wither side prevents my error. If you put it into an answer ill mark it for you as the correct answer. Manyt thanks sir – SQL_Kid Jul 03 '15 at 14:20
  • I've got an answer up, I'll edit in some code shortly. – Michael McGriff Jul 03 '15 at 14:21

4 Answers4

0

You can use a subselect for this.

Select *
FROM AnswersTable
JOIN ( SELECT * FROM LK_Questions Where QuestionTypeID = 1) as LK_Questions
    ON AnswersTable.QuestionID = LK_Questions.QuestionID
JOIN LK_Answers
    ON AnswersTable.Answer = LK_Answers.AnswerID
Ionic
  • 3,884
  • 1
  • 12
  • 33
  • Unfortunately this does not work either, I have tried this already. I should have put that in my original description, sorry – SQL_Kid Jul 03 '15 at 14:01
0

You are joining the ID field of the lookup table against the answer field of the answer table. Is this OK?

lukiller
  • 1,107
  • 9
  • 12
  • 1
    This should be a comment rather than an answer in which you are actually asking a question. – Radu Gheorghiu Jul 03 '15 at 14:01
  • Yes because the answer in the Answerstable will always be an interger (Due to the where), its just stored as varchar but implicitly converts – SQL_Kid Jul 03 '15 at 14:04
0

Pay attention to those fields;

AnswersTable.QuestionID, LK_Questions.QuestionID
AnswersTable.Answer , LK_Answers.AnswerID and LK_Questions.QuestionTypeID 

are they sharing the same datatype?

if so, you should change your query like;

     SELECT * FROM AnswersTable RIGHT JOIN LK_Questions ON LK_Questions.QuestionTypeID = AnswersTable.QuestionID JOIN LK_Answers ON AnswersTable.Answer = LK_Answers.AnswerID where LK_Questions.QuestionTypeID = 1   
sulhadin
  • 521
  • 4
  • 16
  • What is the datatype of AnswersTable.Answer ? – sulhadin Jul 03 '15 at 14:12
  • The QuestionTypeID is not the same as the question type, and a right join is not what I need as I only want matches, I am not interested in questions that have not been answered. Suljadin, the datatype of Answer is Varchar but it converts itself to interger – SQL_Kid Jul 03 '15 at 14:17
  • I was trying to make sure that those that are you compare are the same datatype. otherwise join statement fails. – sulhadin Jul 06 '15 at 05:58
0

The issue in your query is that you have a datatype mismatch on the columns you're using to join your tables together.

One of the easiest ways to correct this is to explicitly CAST both sides of the join to VARCHAR so that there is no problem matching datatypes when joining. This isn't ideal, but if you're not able to change the table schema then you have to work around it.

SQL Fiddle Demo

CREATE TABLE LeftTable
(
  id INT
);

CREATE TABLE RightTable
(
  id VARCHAR(30)
);

INSERT INTO LeftTable (id)
VALUES (1), (2), (3), (4), (5);

INSERT INTO RightTable (id)
VALUES ('1'), ('2'), ('3'), ('4'), ('5'), (',879');

SELECT l.*, r.*
FROM LeftTable l
JOIN RightTable r ON CAST(l.id AS VARCHAR(30)) = CAST(r.id AS VARCHAR(30))
WHERE l.id = '1'
Michael McGriff
  • 793
  • 10
  • 20
  • Thanks Michael this works. I tried to do it backwards (i.e convert the answer stored as text to an int) however this failed. But converting both to Varchar worked for me – SQL_Kid Jul 03 '15 at 14:28