SQL Why is my SELECT selecting duplicate rows? - sql

This is a sub query:
SELECT t1.element_mark, t1.element_length, t1.element_width, t1.element_height, t1.product, t1.mass FROM IMP_ELEMENT as t1 WHERE TRIM(t1.project) = '99999';
This is the result:
This is my second sub query:
SELECT t2.element_id, t2.building, t2.floor_id, t2.deleted, t2.ELEMENT_MARK
FROM IMP_MODEL_GEOMETRY as t2
WHERE TRIM(t2.project) = '99999' AND TRIM(t2.building) = '1' AND TRIM(CAST(t2.floor_id AS VARCHAR(MAX))) = '1' AND t2.deleted = 0
ORDER BY t2.ELEMENT_MARK;
This is the result:
Now i'd like to combine them:
SELECT t1.element_mark, t1.element_length, t1.element_width, t1.element_height, t1.product, t1.mass, t2.element_id, t2.building, t2.floor_id, t2.deleted
FROM IMP_ELEMENT as t1
LEFT JOIN IMP_MODEL_GEOMETRY as t2 ON t1.element_mark = t2.element_mark
WHERE TRIM(t2.project) = '99999' AND TRIM(t2.building) = '1' AND TRIM(CAST(t2.floor_id AS VARCHAR(MAX))) = '1' AND t2.deleted = 0
ORDER BY t2.element_id;
And this is the result:
So what do i want?
I want only one result per "element_id".
I first want to SELECT"element_id" and then i want to find a match in the second table. To find a match i will use "element_mark". What is wrong in my query? why do i get multiple element_id?

As suggested by one of the comments, you probably have missed the WHERE clause in the first table. Try this query instead:
SELECT
t1.element_mark, t1.element_length, t1.element_width, t1.element_height, t1.product, t1.mass, t2.element_id, t2.building, t2.floor_id, t2.deleted
FROM
IMP_ELEMENT as t1
LEFT JOIN
IMP_MODEL_GEOMETRY as t2
ON
t1.element_mark = t2.element_mark
WHERE
TRIM(t2.project) = '99999' AND
TRIM(t2.building) = '1' AND
TRIM(CAST(t2.floor_id AS VARCHAR(MAX))) = '1' AND
t2.deleted = 0 AND
TRIM(t1.project) = '99999'
ORDER BY t2.element_id;

When joining two tables, in your case with a left join, if there are multiple matches on the join condition, multiple rows will be in the result set. You are joining based on element_mark- so for the first record of the first query- 3 rows will be returned in your result. What I would suggest is put the second table at the left part of the query or do a RIGHT JOIN. This way, because element_mark looks unique in the first table, you will get one record per element_id.

If you want to keep all elements and get matching information -- if any -- from the second table, then you want the LEFT JOIN. However, all conditions on the second table need to be in the ON clause:
SELECT t1.element_mark, t1.element_length, t1.element_width, t1.element_height, t1.product, t1.mass,
t2.element_id, t2.building, t2.floor_id, t2.deleted
FROM IMP_ELEMENT t1 LEFT JOIN
IMP_MODEL_GEOMETRY t2
ON t1.element_mark = t2.element_mark AND
TRIM(t2.project) = '99999' AND
TRIM(t2.building) = '1' AND
TRIM(CAST(t2.floor_id AS VARCHAR(MAX))) = '1' AND
t2.deleted = 0
ORDER BY t2.element_id;
There is no WHERE clause because all the filters are on the second table.

Related

single-row subquery returns more than one row in Redshift when I try to use CASE in UPDATE

I am trying to use a case statement with sub query in a Update statement but I am facing an Issue like
single-row sub query returns more than
Please find my Query which I tried
update r_gl.ac
set meeting_cost = case currency_code when 'IND'
then amount
else round(tgt.amount)
from r_gl.ac tgt
join
(
select distinct
a.frm_cur,
a.to_cur,
a.exch_rate
from b_gl.currncy_conv_dim a
join r_gl.ac b
on (a.frm_cur = 123 and a.to_cur = b.cur_cd and f_rate = 'ABC')
join b_gl.int_fg
on b.in_s=c.in_s and a.cal_sk = trunc(c.intact_dt_key,-2)
) src
on tgt.cur_cd=src.to_cur
)
end
Please help me to solve this issue
Your current CASE expression is missing its END. That aside, I see even bigger problems with your UPDATE statement. Redshift is based on an old version of Postgres, and hence I expect that it would adhere to the same syntax Postgres would use for an update join:
UPDATE table1 AS t1
SET some_column = t2.some_other_column
FROM table2 AS t2
WHERE t1.id = t2.id
Applying this syntax to your current query along with the fix for the CASE expression leaves us with the following:
update r_gl.ac tgt
set meeting_cost = case when currency_code = 'IND'
then tgt.amount
else round(tgt.amount) end
from
(
select distinct
a.frm_cur,
a.to_cur,
a.exch_rate
from b_gl.currncy_conv_dim a
inner join r_gl.ac b
on (a.frm_cur = 123 and a.to_cur = b.cur_cd and f_rate = 'ABC')
inner join b_gl.int_fg
on b.in_s=c.in_s and a.cal_sk = trunc(c.intact_dt_key,-2)
) src
where tgt.cur_cd = src.to_cur
The table to which you are joining r_gl.ac has no effect on the data being used to update, but rather would only affect the update by targeting certain rows. If this be not your intended logic, then you might have to rethink the entire query.

JOIN query with WHERE clause returns fewer results than expected in MS Access

First query:
SELECT
TAB1.[CDNO], TAB1.[IDTNO],
IIF(ISNULL([TAB1.ECONIV3]), [TAB1.ECONIV2], 'none') AS [CONTRIB]
FROM
TAB1
WHERE
(TAB1.[UNNN] <> "WATER" AND TAB1.[CCCCPP] <> "SALT")
;
Second query:
SELECT
TAB1.[CDNO], TAB1.[IDTNO], IIF(ISNULL([TAB1.ECONIV3]), [TAB1.ECONIV2], 'none') AS [CONTRIB]
, IIF(ISNULL([TAB2.ENTCOM3]), [TAB1.ENTCOM2],'none') AS [CONCOM] , IIF(ISNULL([TAB2.ENTSTI3]), [TAB1.ENTSTI2],'none') AS [CONSTI]
FROM
TAB1
LEFT OUTER JOIN TAB2
ON (TAB1.[IDTNO] = TAB2.[PTDINO] AND (IIF(ISNULL([TAB1.ECONIV3]), [TAB1.ECONIV2], 'none') = IIF(ISNULL([TAB2.ENTSTI3]), [TAB1.ENTSTI2],'none'))
WHERE ( TAB1.[UNNN] <> "WATER" AND TAB1.[CCCCPP] <> "SALT")
;
TAB1 was has 8 times the number of rows of TAB2.
There is something wrong with the second query has it returns less rows than the first query.
So my issue is in the second query where I'm trying to have all the rows of the selected column of TAB1 with in addition the two columns from
TAB2 with a match on the 2 OUTER JOIN conditions.
Second query shouldn't run because it has an odd number of parentheses (meaning you're missing one), based on what you said here is the updated query:
SELECT TAB1.[CDNO]
, TAB1.[IDTNO]
, IIF(ISNULL([TAB1.ECONIV3]), [TAB1.ECONIV2], 'none') AS [CONTRIB]
, IIF(ISNULL([TAB2.ENTCOM3]), [TAB1.ENTCOM2],'none') AS [CONCOM]
, IIF(ISNULL([TAB2.ENTSTI3]), [TAB1.ENTSTI2],'none') AS [CONSTI]
FROM
TAB1
LEFT OUTER JOIN TAB2
ON (TAB1.[IDTNO] = TAB2.[PTDINO]) AND (IIF(ISNULL([TAB1.ECONIV3]), [TAB1.ECONIV2], 'none') = IIF(ISNULL([TAB2.ENTSTI3]), [TAB1.ENTSTI2],'none'))
WHERE ( TAB1.[UNNN] <> "WATER" AND TAB1.[CCCCPP] <> "SALT")
By your description my first guess is something is turning the outer join into an inner join, but you don't reference the outer table at all in the where clause. I don't suppose there is any more to the where clause or a group by statement that's not included in the above example?

SQL: Want to alter the conditions on a join depending on values in table

I have a table called Member_Id which has a column in it called Member_ID_Type. The select statement below returns the value of another column, id_value from the same table. The join on the tables in the select statement is on the universal id column. There may be several entries in that table with this same universal id.
I want to adjust the select statement so that it will return the id_values for entries that have member_id_type equal to '7'. However if this is null then I want to return records that have member_id_type equal to '1'
So previously I had a condition on the join (commented out below) but that just returned records that had member_id_type equal to '7' and otherwise returned null.
I think I may have to use a case statement here but I'm not 100% sure how to use it in this scenario
SELECT TOP 1 cm.Contact_Relation_Gid,
mc.Universal_ID,
mi.ID_Value,
cm.First_Name,
cm.Last_Name,
cm.Middle_Name,
cm.Name_Suffix,
cm.Email_Address,
cm.Disability_Type_PKID,
cm.Race_Type_PKID,
cm.Citizenship_Type_PKID,
cm.Marital_Status_Type_PKID,
cm.Actual_SSN,
cm.Birth_Date,
cm.Gender,
mc.Person_Code,
mc.Relationship_Code,
mc.Member_Coverage_PKID,
sc.Subscriber_Coverage_PKID,
FROM Contact_Member cm (NOLOCK)
INNER JOIN Member_Coverage mc (NOLOCK)
ON cm.contact_relation_gid = mc.contact_relation_gid
AND mc.Record_Status = 'A'
INNER JOIN Subscriber_Coverage sc (NOLOCK)
ON mc.Subscriber_Coverage_PKID = sc.Subscriber_Coverage_PKID
AND mc.Record_Status = 'A'
LEFT outer JOIN Member_ID mi ON mi.Universal_ID = cm.Contact_Gid
--AND mi.Member_ID_Type_PKID='7'
WHERE cm.Contact_Relation_Gid = #Contact_Relation_Gid
AND cm.Record_Status = 'A'
Join them both, and use one if the other is not present:
select bt.name
, coalesce(eav1.value, eav2.value) as Value1OrValue2
from BaseTable bt
left join EavTable eav1
on eav1.id = bt.id
and eav1.type = 1
left join EavTable eav2
on eav2.id = bt.id
and eav2.type = 2
This query assumes that there is never more than one record with the same ID and Type.

Link tables based on column value

Is it possible to pull values from 2 different tables based on the value of a column? For example, I have a table with a boolean column that either returns 0 or 1 depending on what the end user selects in our program. 0 means that I should pull in the default values. 1 means to use the user's data.
If my table Table1 looked like this:
Case ID Boolean
====================
1 0
2 1
3 1
4 0
5 0
Then I would need to pull Case IDs 1,4,and 5's corresponding data from table Default and Case IDs 3 and 4's corresponding data from table UserDef. Then I would have to take these values, combine them, and reorder them by Case ID so I can preserve the order in the resulting table.
I am fairly inexperienced with SQL but I am trying to learn. Any help or suggestions are greatly appreciated. Thank you in advance for your help.
Something like this:
SELECT
t1.CaseID
,CASE WHEN t1.Boolean = 1 THEN dt.Col1 ELSE ut.Col1 END AS Col1
,CASE WHEN t1.Boolean = 1 THEN dt.Col2 ELSE ut.Col2 END AS Col2
FROM Table1 t1
LEFT JOIN DefaultTable dt ON dt.CaseID = t1.CaseID
LEFT JOIN UserDefTable ut ON ut.CaseID = t1.CaseID
ORDER BY t1.CaseID
You join on both tables and then use CASE in SELECT to choose from which one to display data.
Option B:
WITH CTE_Combo AS
(
SELECT 0 as Boolean, * FROM Default --replace * with needed columns
UNION ALL
SELECT 1 AS Boolean, * FROM UserDef --replace * with needed columns
)
SELECT * FROM Table1 t
LEFT JOIN CTE_Combo c ON t.CaseID = c.CaseID AND t.Boolean = c.Boolean
ORDER BY t.CaseID
This might be even simpler - using CTE make a union of both tables adding artificial column, and then join CTE and your Table using both ID and flag column.
SELECT t1.CaseID,
ISNULL(td.data, tu.data) userData -- pick data from table_default
-- if not null else from table_user
FROM table1 t1
LEFT JOIN table_default td ON t1.CaseID = td.CaseID -- left join with table_default
AND t1.Boolean = 0 -- when boolean = 0
LEFT JOIN table_user tu ON t1.CaseID = tu.CaseID -- left join with table_user
AND t1.Boolean = 1 -- when boolean = 1
ORDER BY t1.CaseID

Combine two different select statements, one distinct the other not

I have two selects which are required to filter data. They are not complicated:
"SELECT * FROM StevesTable t WHERE "
"t.data1 = '%s' AND "
"t.data2 = to_date('%s','DD/MM/YYYY');",
strdata1,
dtDate.Format();
and
SELECT distinct data1 FROM anothertable ftt
join table1 tab on tab.somedata = ftt.somedata
where tab.somedata = 0
and tab.someotherdata = 1
I would like to combine these two as I need to filter the returned dataset from the first select statement by the returned field in the second (ie if a record returned in the first set does not have a data1 value which is contained in the second returned set it is invalid).
I tried to union and intersect the selects but you need the same number of columns returned and that cannot happen as these are completely different tables. When I tried to simply merge them together I found it difficult as the second select statement is a distinct select whereas the first is not.
I was wondering whether I had missed a trick somewhere for combining these sorts of selects?
What you need is a SQL sub-query:
SELECT * FROM StevesTable t
WHERE t.data1 = '%s'
AND t.data2 = to_date('%s','DD/MM/YYYY')
AND t.data1 in (select distinct data1 FROM anothertable ftt
join table1 tab on tab.somedata = ftt.somedata
where tab.somedata = 0
and tab.someotherdata = 1)
There, you check that all records in the first select have a data1 value in the second set.
You can do this using an EXISTS condition:
SELECT * FROM StevesTable t
WHERE t.data1 = '%s' AND
t.data2 = to_date('%s','DD/MM/YYYY') AND
EXISTS (select null
from anothertable ftt
join table1 tab on tab.somedata = ftt.somedata
where tab.somedata = 0 and
tab.someotherdata = 1 and
ftt.data1 = t.data1)