I've been asked to find if totals from one table exceed a certain value. However the identifier I need to group these is stored in another table. So I've figured how to isolate what I need and then copy into excel. However I do understand the principle of summing in SQL, as I've made my own queries that look like this:
SELECT * FROM
(SELECT ID, SUM(Table1.Amount) AS Subtotal FROM Table1 WHERE LineNumber = 1 GROUP BY ID) AS a, Table2 AS b
WHERE a.ID = b.ID
AND a.Subtotal > b.Threshold
In this case, the totals I need to sum all have the same LineNumber from the original table (Table1) so it's easy to compare to a value in a different table. What I want to do is be able to is join a subquery back to the original table, then GROUPBY the identifier and sum from the other table, adding a criteria that the original ID from table one must be a duplicate:
SELECT * FROM
((Table1 as t
INNER JOIN
(SELECT ID FROM Table1
GROUP BY ID HAVING COUNT(ID) >1) as b
ON t.ID = b.ID
Joining criteria back to the original table, I need to do this because the table I need to sum doesn't contain ID,
INNER JOIN Table2 as c
ON t.ID2 = c.ID2
WHERE c.LineNumber = 4
This is where I'm stuck. I want to sum all the LineNumber = 4 for each ID. Again, I had to join using ID2 because ID1 isn't in Table2
Perhaps I'm making this too complicated? Any suggestions would be welcome
Thanks!
Related
I am trying to retrieve the IDs from a table in Oracle only IF another column value doesn't exist in any of the joined tables. Let me give you an example:
example
As you can see in the sketch, Table A is joined to tables B via the ID. I would like to get the IDs from Table A only if all statuses in any joined Table B DO NOT contain the value 2.
Here is my SQL statement:
SELECT ID FROM TABLE A
LEFT JOIN TABLE B
ON A.ID = B.REF_ID
WHERE B.STATUS NOT IN (2)
Unfortunately, I still get all IDs (which makes sense) and am not able to come up with a method to retrieve only the IDs without a certain value in the Status column of a joined table. Hence, I would only like to get ID 1, since all joined tables do not contain the value 2 in their Status.
Many thanks for any inputs.
Use aggregation
SELECT ID
FROM TABLE A LEFT JOIN
TABLE B
ON A.ID = B.REF_ID
GROUP BY A.ID
HAVING SUM(CASE WHEN B.STATUS IN (2) THEN 1 ELSE 0 END) = 0;
Or, simply use NOT EXISTS:
SELECT A.ID
FROM TABLE A
WHERE NOT EXISTS (SELECT 1
FROM B
WHERE A.ID = B.REF_ID AND B.STATUS IN (2)
);
I face issue about duplicate data when join table, here my sample data table I have
-- Table A
I want to join with
-- Table B
this my query notation for join both table,
select a.trans_id, name
from tableA a
inner join tableB b
on a.ID_Trans = b.trans_id
and this the result, why I get the duplicating data which should show only two lines of data, please help me to solve this case.
Firstly, as you have been told multiple times in the comments, this is working exactly as you have written, and (more importantly) as intended. You have 2 rows in tableA and those 2 rows match 2 rows in your table tableB according to the ON clause. This means that each join operation, for the each of the rows in tableA, results in 2 rows as well; thus 4 rows (2 * 2 = 4).
Considering that your table, TableA only has one column then it seems that you should be cleaning up that data and deleting the duplicates. There are plenty of examples on how to do that already (example).
Perhaps the column you show us in TableA is one many, and thus instead you have a denormalisation issue, and instead there should be another table with the details of Id_trans and a PRIMARY KEY or UNIQUE CONSTRAINT/INDEX on it. Then you would join fron that table to TableB.
Finally, what you might be after is an EXISTS, which would look like this:
SELECT B.trans_id, B.[name]
FROM dbo.TableB B
WHERE EXISTS(SELECT 1
FROM dbo.TableA A
WHERE A.ID_Trans = B.trans_id); --Odd that it's called ID_Trans in one table, and Trans_ID in another
As the comments mentioned your query does exactly what you asked it to do but I think you wanted something like:
select a.trans_id, a.name, b.name
from tableA a
inner join tableB b on a.trans_id = b.trans_id
group by a.trans_id, a.name, b.name
Since there are two rows in both table with same ID join will make them four. You can use distinct to remove duplicates:
select distinct a.trans_id, name
from tableA a
inner join tableB b
on a.id_trans = b.trans_id
But I would suggest to use exists:
select trans_id, name
from tableB b
exists (select 1 from tableA a where a.trans_id=b.trans_id)
Table A has 2500 rows
Table B has 12000 rows
Common column between these two tables is Email_ID.
Note: Email ID column may have nulls in table B.
If I join these tables using this query
Select count(*)
from A
left join B on A.Email_ID = B.Email_ID
it is returning a value of more than 2500 records.
But I want only 2500 records from Table A
Please suggest how to do this.
* will return total record count regardless of duplicate or nulls :
Select count(b.Email_ID) -- if you have a duplicate email ids then use `distinct`
from A left join
B
on A.Email_ID = B.Email_ID;
However, you can also use exists, join will return multiple rows if b table has more rows matching email id available in table a. So, count will always be increased.
select count(a.Email_ID)
from a
where exists (select 1 from b where b.Email_ID = a.Email_ID);
If you want only 2,500 hundred records, then why are you joining? That is, these return 2,500:
select count(*)
from A;
select count(distinct A.Email_id)
from A left join
B
on A.Email_ID = B.Email_ID;
If you actually want one row returned from B for each A, then use outer apply rather than left join:
select . . .
from a outer apply
(select top (1) b.*
from b
where b.email_id = a.email_id
) b;
This returns an arbitrary matching row from b. Normally, the subquery would have an order by to provide more control over the matching row. For instance, order by newid() would return a random row.
How I can select a set of rows where each row match a different condition?
Example:
Supposing I have a table with a column called name, I want the result ONLY IF the first row name matches 'A', the second row name matches 'B' and the third row name matches 'C'.
Edit:
I want to do this to work without a fixed size, but in a way I can define the sequence like R,X,V,P,T and it matches the sequence, each one in a row, but in the order.
you can, but probably not in a way you would want:
if your table has a numeric id field, that is incremented with each row, you can self join that table 3 times (lets say as "a", "b" and "c") and use the join condition a.id + 1 = b.id and b.id + 1 = c.id and put you filter in a where clause like: a.name = 'A' AND b.name = 'B' AND c.name = 'C'
but don't expect performance ...
Assuming that You know how to provide a row number to your rows (ROW_NUMBER() in SQL Server, for instance), You can create a lookup (match) table and join on it. See below for explanation:
LookupTable:
RowNum Value
1 A
2 B
3 C
Your SourceTable source table (assuming You already added RowNum to it-in case You didn't, just introduce subquery for it (or CTE for SQL Server 2005 or newer):
RowNum Name
-----------
1 A
2 B
3 C
4 D
Now You need to inner join LookupTable with your SourceTable on LookupTable.RowNum = SourceTable.RowNum AND LookupTable.Name = SourceTable.Name. Then do a left join of this result with LookupTable on RowNum only. If there is LookupTable.RowNum IS NULL in final result then You know that there is no complete match on at least one row.
Here is code for joins:
SELECT T.*, LT2.RowNum AS Matched
FROM LookupTable LT2
LEFT JOIN
(
SELECT ST.*
FROM SourceTable ST
INNER JOIN LookupTable LT ON LT.RowNum = ST.RowNum AND LT.Name = ST.Name
) T
ON LT2.RowNum = T.RowNum
Result set of above query will contain rows with Matched IS NULL if row is not matching condition from LookupTable table.
I suppose you could do a sub query for each row, but it wouldn't perform well or scale well at all and would be hard to maintain.
This may be close to what your after... but I need to know where you're getting your values for A, B, C etc...
Select [insert your fields here]
FROM
(Select T1.Name, T1.Age, RowNum as t1RowNum from T T1 order by name) T1O
Full Outer JOIN
(Select T2.Name, T2.Age, RowNum as T2rowNum From T T2 order By name) T2O
ON T1O.T1RowNum+1 = T2O.T2RowNum
I have several tables that I am joining that I need to add another table to and I can't seem to get the right query. Here is what I have now -
Table 1
carid, catid, makeid, modelid, caryear
Table 2
makeid, makename
Table 3
modelid, modelname
Table 4
catid, catname
The query I am using to join these is:
SELECT * FROM table1 a
JOIN table2 b on a.makeid=b.makeid
JOIN table3 c on a.modelid=c.modelid
JOIN table4 d on a.catid=d.catid
WHERE a.carid = $carid;
Now I need to add a 5th table that I am getting from a 3rd party that I am having a hard time adding to my existing query. The new table has these fields -
Table 5
id, year, make, model, citympg, hwympg
I need the citympg and hwympg based on caryear from table 1, makename from table 2, and modelname from table 3. I know I can do a second query with those values, but I would prefer to do a single query and have all of the data in a single row. Can this be done in a single query? If so, how?
it's possible to have more than condition in a join.
does this work?
SELECT a.*, e.citympg, e.hwympg
FROM table1 a
JOIN table2 b on a.makeid=b.makeid
JOIN table3 c on a.modelid=c.modelid
JOIN table4 d on a.catid=d.catid
Join table5 e on b.makename = e.make
and c.modelname = e.model
and a.caryear = e.year
WHERE a.carid = $carid;
...though your question is not clear. Did you only want to join table5 to the others, or was there something else you wanted to do with table5?
Without indexes, It won't be efficient, but you can do
LEFT JOIN table5 ON (table2.make = table5.make AND table3.model = table5.model AND table1.caryear = table5.caryear)
This also assumes the make and models and years strings match exactly.