I am performing a SELECT on two tables, the selection is conditional on the tables' primary ID, so I expect at most 1 result from each query. I'd like to combine the queries into a single SELECT statement. I thought I should do this using a RIGHT (or maybe a LEFT) OUTER JOIN, but this isn't working for me. Any suggestions?
Table A Table B
--------- ----------
ID (pk) | AAttr ID (pk) | BAttr
SELECT AAttr, BAttr
FROM A
RIGHT OUTER JOIN B
ON B.ID = 1
WHERE A.ID = 1
*Edited to include sample cases
For example, if the tables contained the first set of data and querying for an ID of 1, I'd expect:
[null, 'b']
For the second set of data and querying for an ID of 1, I'd expect:
['a', null]
And for the third set of data and querying for an ID of 1, I'd expect:
['a', 'b']
Table A Table B
-------- --------
2 | a 1 | b
3 | c 4 | d
Table A Table B
-------- --------
1 | a 2 | b
3 | c 4 | d
Table A Table B
-------- --------
1 | a 1 | b
3 | c 4 | d
When you join to tables, you need to relate them to each other via a common column. In this case, the ID.
SELECT a.AAttr, b.BAttr
FROM a
LEFT JOIN b
ON a.ID = b.ID
WHERE a.ID = 1;
if IDs in each table are unrelated and you want to combine two unrelated select statements, try this
select
(SELECT top 1 AAttr FROM A where ID = 1) as AAttr,
(SELECT top 1 BAttr FROM B where ID = 1) as BAttr
Related
I have 2 tables:
People:
ID | Name
----------
1 | John
2 | David
3 | Jennifer
another which is has a simple FK to the first
Note:
ID | People_ID | Note
----------------------
1 | 1 | A note
2 | 1 | Another note
3 | 3 | Jen's note
I want to get the note associated with the max(ID) from Note for each person, or a null if no notes, so the desired result is:
People_ID | Name | Note
----------------------------
1 |John | Another Note
2 |David | NULL
3 |Jennifer| Jen's Note
I can perform a join, but can't include David because the max criteria doesn't bring back the null column. Any help please?
That's a left join - and I would recommend pre-aggregating the notes in a subquery:
select p.*, n.*
from people p
left join (
select people_id, max(id) max_note_id
from note
group by people_id
) n on n.people_id = p.id
There are situations where a lateral join would be more efficient:
select p.*, n.*
from people p
outer apply (
select top(1) id max_note_id
from note n
where n.people_id = p.id
order by id desc
) n
The nice thing about the lateral join is that you can easily bring more columns from the top matching record in the note table if you want to (like the text of the note, or else).
You can use below query:
Demo
SELECT A.NAME, A.ID, MAX(B.ID) FROM PEOPLE A LEFT OUTER JOIN NOTE B
ON (A.ID = B.PEOPLE_ID) GROUP BY A.NAME, A.ID;
What i am trying to do is always sending Product with 0 quantity to the end of an already sorted temp Table without losing current sorting (as i described in the following question How to send Zero Qty Products to the end of a PagedList<Products>?)
I have one Sorted temptable which is filled (it is sorted by what user has selected like Alphabetic , by Price or by Newer product,sorting is based identity id) :
CREATE TABLE #DisplayOrderTmp
(
[Id] int IDENTITY (1, 1) NOT NULL,
[ProductId] int NOT NULL
)
sorted #DisplayOrderTmp :
+------------+---------------+
| id | ProductId |
+------------+---------------+
| 1 | 66873 | // Qty is 0
| 2 | 70735 | // Qty is not 0
| 3 | 17121 | // Qty is not 0
| 4 | 48512 | // Qty is not 0
| 5 | 51213 | // Qty is 0
+------------+---------------+
I want pass this data to web-page, but before it i need to send product with zero quantity to the end of this list without loosing current Sorting by)
My returned data should be like this (sorting doesn't changed just 0 quantity products went to the end of list by their order):
CREATE TABLE #DisplayOrderTmp4
(
[Id] int IDENTITY (1, 1) NOT NULL,
[ProductId] int NOT NULL
)
+------------+---------------+
| id | ProductId |
+------------+---------------+
| 1 | 70735 |
| 2 | 17121 |
| 3 | 48512 |
| 4 | 66873 |
| 5 | 51213 |
+------------+---------------+
P.S: Its My product Table which i have to inner join with tmptable to find qty of products.
Product Table is like this :
+------------+---------------+------------------+
| id | stockqty | DisableBuyButton |
+------------+---------------+------------------+
| 17121 | 1 | 0 |
| 48512 | 27 | 0 |
| 51213 | 0 | 1 |
| 66873 | 0 | 1 |
| 70735 | 11 | 0 |
+------------+---------------+------------------+
What i have tried so far is this : (it works with delay and has performance issue i almost have 30k products)
INSERT INTO #DisplayOrderTmp2 ([ProductId])
SELECT p2.ProductId
FROM #DisplayOrderTmp p2 with (NOLOCK) // it's already sorted table
INNER JOIN Product prd with (NOLOCK)
ON p2.ProductId=prd.Id
and prd.DisableBuyButton=0 // to find product with qty more than 0
group by p2.ProductId order by min(p2.Id) // to save current ordering
INSERT INTO #DisplayOrderTmp3 ([ProductId])
SELECT p2.ProductId
FROM #DisplayOrderTmp p2 with (NOLOCK) //it's already sorted table
INNER JOIN Product prd with (NOLOCK)
ON p2.ProductId=prd.Id
and prd.DisableBuyButton=1 // to find product with qty equal to 0
group by p2.ProductId order by min(p2.Id) // to save current ordering
INSERT INTO #DisplayOrderTmp4 ([ProductId]) // finally Union All this two data
SELECT p2.ProductId FROM
#DisplayOrderTmp2 p2 with (NOLOCK) // More than 0 qty products with saved ordering
UNION ALL
SELECT p2.ProductId FROM
#DisplayOrderTmp3 p2 with (NOLOCK) // 0 qty products with saved ordering
Is there any way To Avoid creating TempTable in this query? send 0
quantity products of first temptable to the end of data-list without
creating three other tempTable , without loosing current ordering based by Identity ID.
My query has performance problem.
I have to say again that the temptable has a identity insert ID column and it is sorted based sorting type which user passed to Stored-Procedure.
Thank You All :)
Make sure the temp table has an index or primary key with Id as the leading column. This will help avoid sort operators in the plan for the ordering:
CREATE TABLE #DisplayOrderTmp
(
[Id] int NOT NULL,
[ProductId] int NOT NULL
,PRIMARY KEY CLUSTERED(Id)
);
With that index, you should be able to get the result without additional temp tables with reasonable efficiency using a UNION ALL query, assuming ProductID is the Product table primary key:
WITH products AS (
SELECT p2.Id, p2.ProductId, prd.stockqty, 1 AS seq
FROM #DisplayOrderTmp p2
JOIN Product prd
ON p2.ProductId=prd.Id
WHERE prd.stockqty > 0
UNION ALL
SELECT p2.Id, p2.ProductId, prd.stockqty, 2 AS seq
FROM #DisplayOrderTmp p2
JOIN Product prd
ON p2.ProductId=prd.Id
WHERE prd.stockqty = 0
)
SELECT ProductId
FROM products
ORDER BY seq, Id;
You mentioned in comments that you ultimately want a paginated result. This can be done in T-SQL by adding OFFSET and FETCH to the ORDER BY clause as below. However, be aware that pagination over a large result set will become progressively slower the further into the result one queries.
WITH products AS (
SELECT p2.Id, p2.ProductId, prd.stockqty, 1 AS seq
FROM #DisplayOrderTmp p2
JOIN Product prd
ON p2.ProductId=prd.Id
WHERE prd.stockqty > 0
UNION ALL
SELECT p2.Id, p2.ProductId, prd.stockqty, 2 AS seq
FROM #DisplayOrderTmp p2
JOIN Product prd
ON p2.ProductId=prd.Id
WHERE prd.stockqty = 0
)
SELECT ProductId
FROM products
ORDER BY seq, Id
OFFSET #PageSize * (#PageNumber - 1) ROWS
FETCH NEXT #PageSize ROWS ONLY;
You could use ORDER BY without using UNION ALL:
SELECT p2.ProductId
FROM #DisplayOrderTmp p2
JOIN Product prd
ON p2.ProductId=prd.Id
ORDER BY prd.DisableBuyButton, p2.id;
DisableBuyButton = 0 - qnt > 0
DisableBuyButton = 1 - qnt = 0
Seems it only needs an extra something in the order by.
An IIF or CASE can be used to give a priority to the sorting.
SELECT tmp.ProductId
FROM #DisplayOrderTmp tmp
JOIN Product prd
ON prd.Id = tmp.ProductId
AND prd.DisableBuyButton IN (0,1)
ORDER BY IIF(prd.DisableBuyButton=0,1,2), tmp.id;
I have an immense doubt, is it possible to create a column calculated using two tables?
Table 1:
---------------------
id | Value1 |
---------------------
1 | 25 |
Table 2
---------------------
id | Value2 |
---------------------
1 | 5 |
Now, in a 3rd table I want a calculated column of the values āā1 and 2?? is it possible?
Table 3
---------------------
id | Sumvalues |
---------------------
1 | ? |
or is there another method that can be used for "sumvalues" to self-adjust with the change of the other fields related to it?
The best option is to create a view in my opinion:
create view vMyView as
select T1.id,
T1.Value1 + T2.Value2
from [Table1] T1 join [Table2] T2 on T1.id = T2.id
This way, everytime you execute query against the view, you will get most actual data.
Use for adding value1 to value2:
SET #value1 = SELECT value1 FROM TABLE1;
SET #value2 = SELECT value2 FROM TABLE2;
SET #value3 = #value1+#value2;
INSERT INTO TABLE3 (value3) VALUES (#value3);
This may contain typos since Iām writting from a cell phone.
What I need to do is the following:
I have in my database a table like this:
idx | name | age
------ ---------- -------
1 | John | 18
2 | Marry | 19
3 | Eric | 17
Then I get a secondTable:
name | age
------ -----
Moses | 29
John | 18
Eric | 20
I would like to run an except query like:
select *
from firstTable
where (name, age) not in (select * from secondTable)
and an intersect query like this:
select *
from firstTable
where (name, age) in (select * from secondTable)
So the result for the first query will be:
2 | Marry | 19
---- -------- ----
3 | Eric | 17
and the result for the second query will be:
1 | John | 18
I've also found a solution that recommends on the following:
select *
from firstTable
where EXISTS (select 1
from secondTable
where firstTable.name = secondTable.name
and firstTable.age = secondTable.age))
but then if I have on both tables "john - null" it will treat them as unknown (neither equal nor un-equal). I know the reason for that, but I do need them to be equal.
The reason I need to do this is in order to preserve the current index values to the query's result.
You just need to include handling the NULL values into your query logic. It would be like so:
SELECT *
FROM firstTable
WHERE EXISTS (SELECT TOP(1) 1
FROM secondTable
WHERE firstTable.name = secondTable.name
AND (
firstTable.age = secondTable.age
OR
(firstTable.age IS NULL AND secondTable.age IS NULL)
)
);
Should work like a charm. =)
Try this:
select distinct a.idx,a.name,a.age,b.name,b.age from first_table as a
inner join
second_table as b
on a.name = b.name and a.age = b.age
This one display only the record with same value both first_table and second_table
And this query Display not in second_table and union both table if has:
select distinct a.idx,b.name,b.age from first_table as a
inner join
second_table as b
on a.name = b.name and a.age = b.age
union all
select a.idx,a.name,a.age
from first_table as a where a.name not in(select name from second_table)
I've searched high and low for an answer to this so apologies if it's already answered!
I have the following result from a query in SQL 2005:
ID
1234
1235
1236
1267
1278
What I want is
column1|column2|column3|column4|column5
---------------------------------------
1234 |1235 |1236 |1267 |1278
I can't quite get my head around the pivot operator but this looks like it's going to be involved. I can work with there being only 5 rows for now but a bonus would be for it to be dynamic, i.e. can scale to x rows.
EDIT:
What I'm ultimately after is assigning the values of each resulting column to variables, e.g.
DECLARE #id1 int, #id2 int, #id3 int, #id4 int, #id5 int
SELECT #id1 = column1, #id2 = column2, #id3 = column3, #id4 = column4,
#id5 = column5 FROM [transposed_table]
You also need a value field in your query for each id to aggregate on. Then you can do something like this
select [1234], [1235]
from
(
-- replace code below with your query, e.g. select id, value from table
select
id = 1234,
value = 1
union
select
id = 1235,
value = 2
) a
pivot
(
avg(value) for id in ([1234], [1235])
) as pvt
I think you'll find the answer in this answer to a slightly different question: Generate "scatter plot" result of members against sets from SQL query
The answer uses Dynamic SQL. Check out the last link in mellamokb's answer: http://www.sqlfiddle.com/#!3/c136d/14 where he creates column names from row data.
In case you have a grouped flat data structure that you want to group transpose, like such:
GRP | ID
---------------
1 | 1234
1 | 1235
1 | 1236
1 | 1267
1 | 1278
2 | 1234
2 | 1235
2 | 1267
2 | 1289
And you want its group transposition to appear like:
GRP | Column 1 | Column 2 | Column 3 | Column 4 | Column 5
-------------------------------------------------------------
1 | 1234 | 1235 | 1236 | 1267 | 1278
2 | 1234 | 1235 | NULL | 1267 | NULL
You can accomplish it with a query like this:
SELECT
Column1.ID As column1,
Column2.ID AS column2,
Column3.ID AS column3,
Column4.ID AS column4,
Column5.ID AS column5
FROM
(SELECT GRP, ID FROM FlatTable WHERE ID = 1234) AS Column1
LEFT OUTER JOIN
(SELECT GRP, ID FROM FlatTable WHERE ID = 1235) AS Column2
ON Column1.GRP = Column2.GRP
LEFT OUTER JOIN
(SELECT GRP, ID FROM FlatTable WHERE ID = 1236) AS Column3
ON Column1.GRP = Column3.GRP
LEFT OUTER JOIN
(SELECT GRP, ID FROM FlatTable WHERE ID = 1267) AS Column4
ON Column1.GRP = Column4.GRP
LEFT OUTER JOIN
(SELECT GRP, ID FROM FlatTable WHERE ID = 1278) AS Column5
ON Column1.GRP = Column5.GRP
(1) This assumes you know ahead of time which columns you will want ā notice that I intentionally left out ID = 1289 from this example
(2) This basically uses a bunch of left outer joins to append 1 column at a time, thus creating the transposition. The left outer joins (rather than inner joins) allow for some columns to be null if they don't have corresponding values from the flat table, without affecting any subsequent columns.