SQL query to get ID from multiple inputs - sql

I'm not sure the title is clear, but this is the situation.
I have a table that looks like this:
ID inputID value
4 1 10
4 2 20
4 3 100
6 1 15
6 2 20
6 3 44
I have user input that gives me the values for inputID 1 and inputID 2, after which I want to get the ID to get the other information corresponding to that ID.
Example: If the user gives inputID(1)=10, inputID(2)=20, I want to get 4
Using simple AND statements don't solve this problem. I have asked already asked a few people, but I can't seem to solve this seemingly simple problem.

What about something like this?
SELECT t1.ID
FROM table t1
INNER JOIN table t2
ON t1.ID = t2.ID
WHERE
t1.inputID = 1 AND t1.value = #input1 AND
t2.inputID = 2 AND t2.value = #input2

select ID from T as T1
where inputID=1 and value=10
and EXISTS(select id from T where ID=T1.ID and inputID=2 and value=20)

Try this query:
Create Table #tmp ( Id int, inputId int, value int)
insert into #tmp values (4,1,10)
insert into #tmp values (4,2,20)
insert into #tmp values (4,3,100)
insert into #tmp values (6,1,15)
insert into #tmp values (6,2,20)
insert into #tmp values (6,3,44)
-- my query
Select top 1 id from
(Select id,count(id) as cnt from #tmp where (inputId=1 and value=10) OR (inputId=2 and value=20) Group by id) tbl
order by cnt desc
-- Scoregraphic's query
SELECT t1.ID
FROM #tmp t1
INNER JOIN #tmp t2
ON t1.ID = t2.ID
WHERE
t1.inputID = 1 AND t1.value = 10 AND
t2.inputID = 2 AND t2.value = 20
Drop table #tmp
On seeing the execution plan my query is takes overall 23% and ScoreGraphic's query takes 21%

Related

Find Products customer bought together but non repeating columns

I am using SQL Server and I'm trying to find out the top 2 products that are being bought the most together
This is a product table
I want it to be displayed as shown below:
I have tried
SELECT TOP 2 Product_Id, bought_with_Product_Id, times_bought_together
FROM PRODUCT
GROUP BY Product_Id, bought_with_Product_Id, times_bought_together
Have tried this as well
SELECT TOP 2 *
FROM Product
WHERE times_bought_together = (SELECT MAX(times_bought_together) FROM product)
AND Product_Id <> bought_with_Product_Id
it returns
How do I make it so that product_id and bought_with_product_Id rows do not overlap
You can exclude the duplicate rows using a NOT EXISTS test e.g.
declare #Test table (id int, otherId int, times int);
insert into #Test (id, otherId, times)
values
(1,2,3),
(2,1,3),
(4,1,2),
(1,4,2),
(1,5,1),
(5,1,1);
select top 2 *
from #Test T1
where not exists (
select 1
from #Test T2
where T1.id = T2.otherId
and T1.otherId = T2.id
-- Keep the duplicate with the lower id
and T2.id < T1.id
);
Returns:
id
otherId
times
1
2
3
1
4
2
Note: Providing the DDL+DML for your test data (as shown here) makes it much easier for people to answer your question.

Insert multiple rows using SQL Merge statement when condition matched

Have Table with Non Identity Primary key. so whenever we insert new record we have to pass Primary key also.
I have to insert into the above table when record is not matched using Merge statement. But the problem is i could not increment the Primary key for each insert. it it throwing can not insert duplicate in Primary key column.
Please find the Sample Merge query below.
Is it possible to insert multiple rows by increment primary key.
MERGE DBO.Table1 T1
USING (DBO.Table2 )T2
ON (T1.ID = T2.ID)
WHEN MATCHED
THEN UPDATE SET
T1.CURVE = T2.CURVE
WHEN NOT MATCHED
THEN INSERT (ID, CURVE )
Values ( T2.ID, T2.CURVE);
The code in your example works, here's a demo easy to reproduce
;with cteT as ( SELECT * FROM (VALUES (1,'T1 Val 1') , (2,'T1 Val 2') , (4,'T1 Val 4') ) as T1(ID, Curve)
)SELECT * INTO #Dest FROM cteT
;with cteT as ( SELECT * FROM (VALUES (3,'T2 Val 3') , (4,'T2 Val 4') , (5,'T2 Val 5') ) as T1(ID, Curve)
)SELECT * INTO #Srce FROM cteT;
MERGE INTO #Dest as T1
USING #Srce as T2 ON T1.ID=T2.ID
WHEN MATCHED THEN UPDATE SET T1.Curve=T2.CURVE
WHEN NOT MATCHED BY TARGET
THEN INSERT (ID, Curve) VALUES(T2.ID, T2.Curve)
;
SELECT * FROM #Dest ORDER BY ID
DROP TABLE #Dest
DROP TABLE #Srce
This is the output, note that for 1 & 2 the value is unchanged, for 4 it's updated from T2, and for 3 and 5 it's inserted from T2.
ID Curve
1 T1 Val 1
2 T1 Val 2
3 T2 Val 3
4 T2 Val 4
5 T2 Val 5
This means that most likely either the problem is in your values for T2.ID or your sample is too pared down and misses a complication in your actual code. I'd start by checking your data in T2.ID
SELECT ID, COUNT(ID) as IDCount FROM DBO.Table2 GROUP BY ID HAVING COUNT(*) > 1
SELECT * FROM DBO.Table2 WHERE ID IS NULL
and see if any records turn up. If those are both empty, look at your actual merge code and see how it might differ from what you posted. If you post updated sample code I'll try to have a look.

How to update in order and query the updated fields when updating in SQL in a single statement

I need to calculate Dividend Factors in the DB and the basic calculation needed in a general way is row2 field2 = (row2's field1) * (row1's field2) where the field2 is the value I need to both update and query at the same time i.e. when I calculate it for one row, I need the calculated value of the previous row for this row.
Now I have a temp table with has all the values and now I need to calculate the final values, but when I tried this:
UPDATE
#temp
SET
field2 = IsNull(
(SELECT d2.field2 * d.field1 FROM #temp AS d2 WHERE d2.rowNr = d.rowNr - 1)
,d.field1
)
FROM
#temp as d
;
It always saw that the field2 was always NULL and went with the default action, with it should do only for the first row.
Now currently there are only two methods I know for doing this:
Loop through the #temp with a cursor
Use a while statement and loop through the table that way (I opted for this one, because I thought there is no point in using a cursor for a small table of 10-20 rows max)
But I still would like to get this into a single statement, but I have no idea how to do this. I am using MS SQL 2008 R2.
EDIT:
This is the actual data I am working with: (Note, that all field2 values are NULL prior to the calculation and the data type is money)
field1 field2(expected values)
------ ----------------------
1,033 1,033
1,0363 1,0705
1,0558 1,1302
1,0157 1,1479
1,0188 1,1695
1,026 1,1999
1,0286 1,2342
1,0323 1,2741
1,0319 1,3147
Okay if I'm understanding this, you want to find field2 which is based on previous rows of field2 that were just calculated so you need either some form of loop or recursion. Try this recursive solution out:
Setting Up Tables
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
DROP TABLE #temp;
DECLARE #yourTable TABLE (ID INT,field1 INT, field2 INT);
INSERT INTO #yourTable(ID,field1,field2)
VALUES (1111,11,11),(2222,22,22),(3333,33,33);
SELECT ROW_NUMBER() OVER (ORDER BY ID) rowNr,
ID,
field1,
field2 INTO #temp
FROM #yourTable;
Calculating values
WITH cte_recursion
AS
(
SELECT TOP 1
rowNR,
ID,
field1,
field2,
field1 AS dividend_factor
FROM #temp A
ORDER BY rowNr
UNION ALL
SELECT B.rowNr,
B.ID,
B.field1,
B.field2,
B.field1 * A.dividend_factor
FROM cte_recursion A
INNER JOIN #temp B
ON A.rowNr = B.rowNr - 1
)
Actual Update
UPDATE #yourTable
SET field2 = B.dividend_factor
FROM #yourTable A
INNER JOIN cte_recursion B
ON A.ID = B.ID
OPTION (MAXRECURSION 0)
SELECT *
FROM #yourTable
Results:
ID field1 field2
----------- ----------- -----------
1111 11 11
2222 22 242
3333 33 7986
Personally I wouldn't use the update because you have to constantly make sure the data is update to date. I'd much rather use the CTE I used to calculate the values and put it in a view so that you know the values are ALWAYS up to date and you don't have to worry about running it. Either that or having a dividend_factor column in your actual table that will be NULL unless the value is updated. Just my two cents
UPDATE d1
SET d1.field2 = IsNull(d2.field2 * d1.field1, d1.field1)
FROM #temp AS d1
left outer join #temp AS d2
on d2.rowNr = d1.rowNr - 1
magic
select d1.field1, EXP(SUM(LOG(d2.field1)))
from #temp AS d1
join #temp AS d2
on d2.rowNr <= d1.rowNr
group by d1.field1
op claims wrong answer
test for youself
drop table #temp;
create table #temp (ID int, val money);
insert into #temp (ID, val) values
(1, 1.033)
, (2, 1.0363)
, (3, 1.0558)
, (4, 1.0157)
, (5, 1.0188)
, (6, 1.026)
, (7, 1.0286)
, (8, 1.0323)
, (9, 1.0319);
SELECT TOP 10 [t1].[ID], EXP(SUM(LOG([t2].[val])))
from #temp AS t1
join #temp AS t2
on t2.[ID] <= t1.[ID]
group by t1.[ID]
order by t1.[ID]

SQL Server 2008 - need help merging 2 tables (cartesian)

I have 2 tables that are not related at all and I need to put them together - one column per table. When I try the cartesian join, I end up with every combination:
SELECT Field1, Field2 FROM Table1, Table2
Result:
Table1.Field1 Table2.Field2
---------------------------
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
I need it to return side-by-side:
Table1.Field1 Table2.Field2
---------------------------
1 1
2 2
3 3
is this possible? Thanks in advance
EDIT
Table1.Table1IDs
----------------
1
2
3
4
5
Table2.Table2IDs
----------------
6
7
8
9
10
Desired output (into a temp table/select statement)
Table1.Table1IDs Table2.Table2IDs
------------------------------------
1 6
2 7
3 8
4 9
5 10
So that I can then do my insert into the actual table I need to do an insert:
INSERT INTO dbo.MTMObjects
SELECT Table1IDs, Table2IDs
FROM [temp table or solution]
ANSWER
Bluefeet gave me the idea to use temp tables with an identity column that i can then use to join. His is 'safer' because you aren't relying on SQL's good humor to sort both recordsets the same, but this might help the next guy:
DECLARE #tmp_Table1 TABLE(ID int IDENTITY(1,1) NOT NULL, TableID1 int NOT NULL)
DECLARE #tmp_Table2 TABLE(ID int IDENTITY(1,1) NOT NULL, TableID2 int NOT NULL)
INSERT INTO #tmp_Table1
OUTPUT INSERTED.Field1
SELECT * FROM Table1
INSERT INTO #tmp_Table2
OUTPUT INSERTED.Field2
SELECT * FROM Table2
OUTPUT
SELECT tmp1.Field1, tmp2.Field2
FROM #tmp_Table1 tmp1 INNER JOIN #tmp_Table2 tmp2 ON tmp2.ID = tmp1.ID
CHEERS!
You can try something like this using row_number(). This will force a relationship between the two tables based on the row_number:
select t1.col1, t2.col2
from
(
select col1, row_number() over(order by col1) rn
from table1
) t1
inner join
(
select col2, row_number() over(order by col2) rn
from table2
) t2
on t1.rn = t2.rn
See SQL Fiddle with Demo
if i understood ...the only you need is to add a filter in where clause
SELECT Field1, Field2 FROM Table1, Table2 WHERE Table1.Field1=Table2.Field2
You should probably change your final solution to use an outer join instead of inner join, in case the tables don't have exactly the same number of rows.

SQLite: accumulator (sum) column in a SELECT statement

I have a table like this one:
SELECT value FROM table;
value
1
3
13
1
5
I would like to add an accumulator column, so that I have this result:
value accumulated
1 1
3 4
13 17
1 18
5 23
How can I do this? What's the real name of what I want to do? Thanks
try this way:
select value,
(select sum(t2.value) from table t2 where t2.id <= t1.id ) as accumulated
from table t1
but if it will not work on your database, just add order by something
select value,
(select sum(t2.value) from table t2 where t2.id <= t1.id order by id ) as accumulated
from table t1
order by id
this works on an oracle ;) but it should on a sqlite too
Here's a method to create a running total without the inefficiency of summing all prior rows. (I know this question is 6 years old but it's one of the first google entries for sqlite running total.)
create table t1 (value integer, accumulated integer, id integer primary key);
insert into t1 (value) values (1);
insert into t1 (value) values (3);
insert into t1 (value) values (13);
insert into t1 (value) values (1);
insert into t1 (value) values (5);
UPDATE
t1
SET
accumulated = ifnull(
(
SELECT
ifnull(accumulated,0)
FROM
t1 ROWPRIOR
WHERE
ROWPRIOR.id = (t1.id -1 )),0) + value;
.headers on
select * from t1;
value|accumulated|id
1|1|1
3|4|2
13|17|3
1|18|4
5|23|5
This should only be run once after importing all the values. Or, set the accumulated column to all nulls before running again.
The operation is called a running sum. SQLite does not support it as is, but there are ways to make it work. One is just as Sebastian Brózda posted. Another I detailed here in another question.