Select distinct values ignoring one field - c#

I have a table similar to this
Table(Id int, PropertyId int, UserId int, AccesedOn datetime)
So the table can have value for one property for one user, but different times.
Eg.
1,100,5, 2012-10-16 16:24:48
2,100,5, 2012-10-17 11:22:00
3,100,5, 2012-10-18 17:10:05
What I am trying here is to select distinct properties for specific user, but order by most recent access time.
Also I am joining this table to three other tables which result in providing duplicate values. Therefore I have to use DISTINCT command.
Problem I have is since I doing the orderby AccesedOn, it need to appear on select statement which doesn’t brings the distinct values since the AccesedOn column have different values.
For above example it should return only 3,100,5, 2012-10-18 17:10:05
Any suggestions to overcome this?

;WITH CTE as(
select *,ROW_NUMBER() over (partition by PropertyId,UserId order by AccesedOn desc) as rn
from table1)
select * from CTE where rn=1

It is more likely that you need a subselect than that you need a distinct for this.
select *
from Table A
where AccessedOn in
(Select max(AccessedOn) from table B where A.UserId = B.UserId)

Instead of using DISTINCT, you can use MAX() and group by the rest of the columns
Select Id, PropertyId, UserId, MAX(AccesedOn)
From Table t
group by Id, PropertyId, UserId
This should give you the results you are looking for.

Related

How DB Manager works to fetch 50 row Oracle Database and implement it in C# [duplicate]

Problem: I need write stored procedure(s) that will return result set of a single page of rows and the number of total rows.
Solution A: I create two stored procedures, one that returns a results set of a single page and another that returns a scalar -- total rows. The Explain Plan says the first sproc has a cost of 9 and the second has a cost of 3.
SELECT *
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY D.ID DESC ) AS RowNum, ...
) AS PageResult
WHERE RowNum >= #from
AND RowNum < #to
ORDER BY RowNum
SELECT COUNT(*)
FROM ...
Solution B: I put everything in a single sproc, by adding the same TotalRows number to every row in the result set. This solution feel hackish, but has a cost of 9 and only one sproc, so I'm inclined to use this solution.
SELECT *
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY D.ID DESC ) RowNum, COUNT(*) OVER () TotalRows,
WHERE RowNum >= from
AND RowNum < to
ORDER BY RowNum;
Is there a best-practice for pagination in Oracle? Which of the aforementioned solutions is most used in practice? Is any of them considered just plain wrong? Note that my DB is and will stay relatively small (less than 10GB).
I'm using Oracle 11g and the latest ODP.NET with VS2010 SP1 and Entity Framework 4.4. I need the final solution to work within the EF 4.4. I'm sure there are probably better methods out there for pagination in general, but I need them working with EF.
If you're already using analytics (ROW_NUMBER() OVER ...) then adding another analytic function on the same partitioning will add a negligible cost to the query.
On the other hand, there are many other ways to do pagination, one of them using rownum:
SELECT *
FROM (SELECT A.*, rownum rn
FROM (SELECT *
FROM your_table
ORDER BY col) A
WHERE rownum <= :Y)
WHERE rn >= :X
This method will be superior if you have an appropriate index on the ordering column. In this case, it might be more efficient to use two queries (one for the total number of rows, one for the result).
Both methods are appropriate but in general if you want both the number of rows and a pagination set then using analytics is more efficient because you only query the rows once.
This may help:
SELECT * FROM
( SELECT deptno, ename, sal, ROW_NUMBER() OVER (ORDER BY ename) Row_Num FROM emp)
WHERE Row_Num BETWEEN 5 and 10;
In Oracle 12C you can use limit LIMIT and OFFSET for the pagination.
Example -
Suppose you have Table tab from which data needs to be fetched on the basis of DATE datatype column dt in descending order using pagination.
page_size:=5
select * from tab
order by dt desc
OFFSET nvl(page_no-1,1)*page_size ROWS FETCH NEXT page_size ROWS ONLY;
Explanation:
page_no=1
page_size=5
OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY - Fetch 1st 5 rows only
page_no=2
page_size=5
OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY - Fetch next 5 rows
and so on.
Refrence Pages -
https://dba-presents.com/index.php/databases/oracle/31-new-pagination-method-in-oracle-12c-offset-fetch
https://oracle-base.com/articles/12c/row-limiting-clause-for-top-n-queries-12cr1#paging
A clean way to organize your SQL code could be trough WITH statement.
The reduced version implements also total number of results and total pages count.
For example
WITH SELECTION AS (
SELECT FIELDA, FIELDB, FIELDC FROM TABLE),
NUMBERED AS (
SELECT
ROW_NUMBER() OVER (ORDER BY FIELDA) RN,
SELECTION.*
FROM SELECTION)
SELECT
(SELECT COUNT(*) FROM NUMBERED) TOTAL_ROWS,
NUMBERED.*
FROM NUMBERED
WHERE
RN BETWEEN ((:page_size*:page_number)-:page_size+1) AND (:page_size*:page_number)
This code gives you a paged resultset with two more fields:
TOTAL_ROWS with the total rows of your full SELECTION
RN the row number of the record
It requires 2 parameter: :page_size and :page_number to slice your SELECTION
Reduced Version
Selection implements already ROW_NUMBER() field
WITH SELECTION AS (
SELECT
ROW_NUMBER() OVER (ORDER BY FIELDA) RN,
FIELDA,
FIELDB,
FIELDC
FROM TABLE)
SELECT
:page_number PAGE_NUMBER,
CEIL((SELECT COUNT(*) FROM SELECTION ) / :page_size) TOTAL_PAGES,
:page_size PAGE_SIZE,
(SELECT COUNT(*) FROM SELECTION ) TOTAL_ROWS,
SELECTION.*
FROM SELECTION
WHERE
RN BETWEEN ((:page_size*:page_number)-:page_size+1) AND (:page_size*:page_number)
Try this:
select * from ( select * from "table" order by "column" desc ) where ROWNUM > 0 and ROWNUM <= 5;
I also faced a similar issue. I tried all the above solutions and none gave me a better performance. I have a table with millions of records and I need to display them on screen in pages of 20. I have done the below to solve the issue.
Add a new column ROW_NUMBER in the table.
Make the column as primary key or add a unique index on it.
Use the population program (in my case, Informatica), to populate the column with rownum.
Fetch Records from the table using between statement. (SELECT * FROM TABLE WHERE ROW_NUMBER BETWEEN LOWER_RANGE AND UPPER_RANGE).
This method is effective if we need to do an unconditional pagination fetch on a huge table.
Sorry, this one works with sorting:
SELECT * FROM (SELECT ROWNUM rnum,a.* FROM (SELECT * FROM "tabla" order by "column" asc) a) WHERE rnum BETWEEN "firstrange" AND "lastrange";

SQL: How to check if all IDs in a list are in a table

first of all I am sorry if this question is too obvious, since I am quite new in SQL.
So, I have a list of IDs (variable, depending how many products the user chooses). And I want to check if all of them are in a table. If one of them is not, the result of the query should be null. If all of them are there, the result should be all the rows where those IDs are.
How can I do this?
Best regards,
Flavio
Do a LEFT JOIN from the list to the table on the ID field. You'll get a null if there is no record
You can even put a WHERE clause like 'WHERE List.ID IS NULL' to only see those that aren't in the table
Edit: Original Poster did not say they were using C# when I wrote this answer
UNTESTED:
Not sure if this is the most efficient but it seems like it should work.
1st it generates a count of items in the table for your list. Next it cross joins the 1 result record to a query containing the entire list ensuring the count matches the count in your provided list and limiting the results to your list.
SELECT *
FROM Table
CROSS JOIN (
SELECT count(*) cnt
FROM table
WHERE ID in (yourlist)) b
WHERE b.cnt = yourCount
and ID IN (YourList)
Running two in statements seems like it would be terribly slow overall; but my first step when writing SQL is usually to get something that works and then seek to improve performance if needed.
Get the list of Ids into a table, (you can pass them as a table variable parameter to a Stored proc), then in the stored proc, write
assuming the list of ids from C# is in table variable #idList
Select * from myTable
Where id in (Select id from #idList)
and not exists
(Select * from #idList
where id Not in
(Select id from myTable))

How can I find the row number of a particular row?

I have a database table like this:
I want to get the the row number of the second row. I use the following code:
SELECT ROW_NUMBER() OVER(ORDER BY Name) From Deposit WHERE Name='Murali'
But, its not working. Whats wrong with the code?
Thanks in advance.
The ROW_NUMBER function returns the row number in the resulting dataset.
In your query you restricted the results to only those whose name is Murali. Since you have only one such record, it is normal that it will return 1.
In SQL there's no such notion as row number. Table rows do not have an order. The notion of order only makes sense when you make a SQL query. Without SQL query you simply cannot talk about order and row numbers.
It appears that you need to introduce some order number for each user. The correct way to implement this is to add an Order column to your Deposit table. Now in order to retrieve it you would use the following query:
SELECT [Order] From Deposit WHERE Name = 'Murali'
All that's left is make the Order column to autoincrement and you are good to go. Everytime a new record is inserted the value will be automatically incremented. So there you go, now you have an order which represents the order in which the records have been inserted into the table. You now have context.
Perhaps something like this (if I understood you correctly):
SELECT Q.RN FROM (
SELECT ROW_NUMBER() OVER(ORDER BY Name) AS RN, * From Deposit
) AS Q
WHERE Q.Name = 'Murali'
Try this
WITH TempTable AS
(
SELECT Name,ROW_NUMBER() OVER (ORDER BY Name) AS 'RowNumber'
FROM Deposit
)
SELECT RowNumber,Name
FROM TempTable
WHERE Name='Murali'

How to select unique values from a table and insert it into another table in firebird?

I have 2 tables in firebird, one of the tables contains the duplicate ID's and the other one only the unique ones. So, I want to use a procedure to select the unique ID's from the duplicates table and insert those into the unique table. But, I don't really know how, can anyone help me?
EDIT: Here is an example:
There are 2 tables
## GASFLESSEN ##
ID CODE SUCCESS TARE_WEIGHT FILLING_NOZZLE //< Column "CODE" contains those unique ID's.
## READINGS ##
ID CODE_ID READING_TIME //< Column "CODE_ID" contains the duplicate ID's
Thanks guys.
If you want to get list of "unique" ID-s in the table where there is dublicates then use DISTINCT, ie
SELECT DISTINCT id FROM d
Now if you want to further restrict the resultset to records which have a id not yet in the "unique table" either join the tables or use NOT EXISTS ie
SELECT DISTINCT id FROM d WHERE NOT EXISTS(SELECT 1 FROM u WHERE u.id = d.id)
procedure CopyUniqueFromData;
declare var_id integer;
for
select distinct id from d into :var_id
do begin
insert into u (id) values (:var_id);
end
end
There are several ways to do this. In addition to the answer of ain this can also be done using MERGE:
MERGE INTO table_unique
USING (SELECT DISTINCT id FROM table_duplicates) src
ON table_unique.id = src.id
WHEN NOT MATCHED THEN
INSERT (id) values (src.id);

Passing Parameters to a Named Command where command text contains IN

How do I pass paramter values for a command where SQL Text contains IN.
i.e. My command SQL text is something like SELECT * FROM USERS WHERE USERID IN (1,2,3).
There are plenty of examples like MSDN has but coudn't find one to pass values for IN. Tried taking a variable and set values as a single string but SQL wont work that way.
You should have a UDF which converts a (for example) csv string into a table of values.
Then, your query can be some thing like:
select *
from yourTable
where yourField IN ( select yourColumn from dbo.yourUDF(yourCSV) )
The short answer is there's no good way to do this.
If you're indeed only working with a list of numeric values, you probably don't need to use parameters as this feature is mainly designed to prevent SQL injection attacks. However, if you have an array of ints, and use that to build your query, you're safe.
The only other way I can think of would be to add one parameter per item. For example:
SELECT * FROM USERS WHERE USERID IN (#p1, #p2, #p3)
Then, loop through your array in C# and create a parameter for each item.
Hope this helps!
This has been asked many, many times. Two ways spring to mind:
If you have SQL2008, you can pass a "table value parameter" (tvp), where your table parameter has the values for your "in" clause, then have a "where" clause that checks values are "in (select whatever from tvp)".
If you do not have SQL2008, you can use a "common table expression" (cte), such as...
declare #t table (xyz varchar(100))
insert into #t values ('hello')
insert into #t values ('there')
insert into #t values ('world')
insert into #t values ('10')
insert into #t values ('20')
insert into #t values ('30')
declare #a as varchar(120)
set #a = 'hello,10,30'
;with cte as
(
select cast(null as varchar(max)) as 'v', 1 as s, charindex(',' , #a, 0) as e
union all
select cast(substring(#a, s, e-s) as varchar(max)), e+1, charindex(',' , #a + ',', e+1)
from cte where e!=0
)
select *
from #t
where (xyz in (select v from cte where v is not null))
In this example (above), the string #a is the comma separated list of values you want for your "in" clause, and the (recursive) cte just strips out the values, one by one. Of course, this is just a quick example and would probably need checks for empty strings, successive commas, and the like.
Of course, the usual caveats apply with regard to using SQL to (effectively) do string manipulation.
Regards,
Ross

Categories