SQL Query to fetch data between starting and ending null - sql

I got a requirement in some project where i need data from a table where i need to select top values that starts after a null value and than again some null values and further data
suppose table name is Data which has a single column named as Company
Company
NULL
NULL
NULL
Google
Microsoft
Oracle
NULL
NULL
Linked In
Twitter
Facebook
NULL
NULL
in simple words i need to write a query that selects {Google, Microsoft and Oracle} as a result and nothing else .... its just a sample data not my actual project
this data can have hundreds of values between starting null and ending null
Please provide your input to write such query
Thanks

Assuming ID is there to keep order... you could do this. This just find the first non-null ID, and then the next null id - 1 as its range.
SELECT *
FROM COMPANY
WHERE ID BETWEEN
( SELECT MIN(ID)
FROM COMPANY
WHERE COMPANY_NAME IS NOT NULL ) AND
( SELECT MIN(ID) - 1
FROM COMPANY
WHERE COMPANY_NAME IS NULL
AND ID > ( SELECT MIN(ID) MIN_ID
FROM COMPANY
WHERE COMPANY_NAME IS NOT NULL ) )
SQL Fiddle Example
Or you could use analytical functions, which would probably be better, assuming you have them in your DBMS.

The easiest way is to use lag():
select d.*
from (select d.*, lag(company) over (order by id) as prev_company
from data d
) d
where prev_company is null and company is not null;
If you don't have lag(), I would use a correlated subquery:
select d.*
from (select d.*,
(select d2.company
from data d2
where d2.id < d.id
order by d2.id desc
limit 1
) as prev_company
from data d
) d
where prev_company is null and company is not null;
Note that in some databases limit might be fetch first row only or select top 1 or some other construct.

Related

SQL check unique key

I hope you're doing fine,
I have a problem to check if my key is unique in my table
Example
ID NAME DATE
1 H 12/12/2022
1 B 11/10/2012
I want to check if the ID can duplicates with other values in Name and Date or not, if all the three are duplicated it's okay, but i want to verify if i can find the same id but with another values.
Thanks
I tried to this :
SELECT ID, NAME , DATE , COUNT(ID)
FROM TABLE t
GROUP BY ID, NAME, DATE
HAVING COUNT(ID) > 1
Try this (For invalid duplicate ID)
SELECT
a.ID, COUNT(1) cnt
FROM TABLE a
INNER JOIN (
SELECT DISTINCT ID, NAME, DATE FROM TABLE
) b ON a.ID = b.ID AND a.NAME != b.NAME AND a.DATE != b.DATE
GROUP BY ID
HAVING COUNT(1) > 1
If your database / table makes any kind of sense it has the feature of primary keys. They MUST be unique and cannot be null. So having a field that is used for IDENTIFYING an entry - thats why it is called ID - please use primary keys in your table and let the DB do it's work.
https://www.w3schools.com/sql/sql_primarykey.ASP
To find id's having invalid duplicate rows, simply do a GROUP BY, and use HAVING to find the invalid rows:
SELECT ID
FROM TABLE
GROUP BY ID
HAVING COUNT(DISTINCT NAME) > 1
OR COUNT(DISTINCT DATE) > 1

LIMIT equivalent for SQL Server 2012 in an UPDATE statement

I have the following table below and am trying to update the first available row with an user ID through a query, but I need to limit this to only update one row and not multiple.
ID Model UserID
1 X12T5 1
2 X13T5 2
3 X14T5 NULL
4 X15T5 NULL
The first available row would be where ID is 3. I would update it with the following query:
UPDATE Table SET UserID = '3' WHERE UserID IS NULL
But I want to make sure it affects only 1 row and not multiple that are available, LIMIT doesn't exist in SQL Server.
What would the best way to achieve this?
You can do this with UPDATE TOP. It's the equivalent of a SELECT TOP but for updates; and TOP is SQL Server's equivalent of MySQL's LIMIT.
See further info.
UPDATE Table SET UserID = '3'
WHERE UserID IS NULL
AND Id IN (SELECT top 1 ID FROM table where UserId IS NULL)
You can also use any of the following methods (Assuming column ID is of integer datatype)
Using subquery :
UPDATE a
SET a.UserID='3'
FROM YourTable a
WHERE ID =( SELECT MIN(ID)
FROM YourTable
WHERE UserID is NULL)
Using JOIN:
UPDATE a
SET a.UserID='3'
FROM YourTable a
JOIN
( SELECT MIN(ID) MinId
FROM YourTable
WHERE UserID is NULL) b
ON a.ID=b.MinId
Using CTE
WITH cte_a
AS
(SELECT MIN(ID) MinId
FROM YourTable
WHERE UserID is NULL)
UPDATE a
SET a.UserID='3'
FROM YourTable a
JOIN cte_a b a.ID=b.MinId
You can also use CTE & perform the SELECT\UPDATE\DELETE operations ,
; WITH CTE AS (
SELECT TOP 10 * FROM TABLE
)
UPDATE CTE
SET ...
DELETE\UPDATE\SELECT works with CTE ... Cool !!!

How to find the first nearest value up and down in SQL?

I have table like this:
When I set id =4 , the results I need are:
Note that I selected the ID=4 and the two nearest values from both sides .
How can write sql code for do it?
You can use LEAD() function , that selects the next value by a specific order , like this:
Note that LEAD was only introduced to SQL-Server 2012+.
SELECT s.id,s.name,s.number
FROM (
SELECT t.*
LEAD(t.id,1) OVER(ORDER BY t.Number DESC) as Next_val,
LEAD(t.id,1) OVER(ORDER BY t.Number) as Last_val
FROM YourTable t) s
WHERE 4 IN(s.id,next_Val,s.last_val)
You can replace 4 with your desired ID or with a parameter .
EDIT: A little explanation - LEAD function provides a way to access the next row, without the use of a SELF JOIN or a sub query , it orders the results by the order you provided inside the OVER() clause, and select the value inside the parentheses - LEAD(value) that belong to the record above the current record that is being processed. So, this query selects each ID , and the ID that belongs to the nearest value up and down , and then check if one of them is your desired ID .
declare #id int = 4
select sn.*
from table sn
inner join
(
select top 2 sn_prev.*
from table sn_prev
where id <= #id
order by id desc
) sp on sp.id= sn.id
union
select sn.*
from table sn
inner join
(
select top 1 sn_prev.*
from table sn_prev
where id > #id
order by id
) sp on sp.id = sn.id
you can use MIN() and MAX() function in sql.

SQL Server 2008 select query difficulty

I have a table with over 100k records. Here my issue, I have a bunch of columns
CompanyID CompanyName CompanyServiceID ServiceTypeID Active
----------------------------------------------------------------
1 Xerox 17 33 Yes
2 Microsoft 19 39 Yes
3 Oracle 22 54 Yes
2 Microsoft 19 36 Yes
So here's how my table looks, it has about 30 other columns but they are irrelevant for this question.
Here's my quandary..I'm trying to select all records where CompanyID and CompanyServiceID are the same, so basically as you can see in the table above, I have Microsoft that appears twice in the table, and has the same CompanyID and CompanyServiceID, but different ServiceTypeID.
I need to be able to search all records where there are duplicates. The person maintaining this data was very messy and did not update some of the columns properly so I have to go through all the records and find where there are records that have the same CompanyID and CompanyServiceID.
Is there a generic query that would be able to do that?
None of these columns are my primary key, I have a column with record number that increments by 1.
You can try something like this:
SELECT CompanyName, COUNT(CompanyServiceID)
FROM //table name here
GROUP BY CompanyName
HAVING ( COUNT(CompanyServiceID) > 1 )
This will return a grouped list of all companies with multiple entries. You can modify what columns you want in the SELECT statement if you need other info from the record as well.
Here's one option using row_number to create the groupings of duplicated data:
select *
from (
select *,
row_number () over (partition by companyId, companyserviceid
order by servicetypeid) rn
from yourtable
) t
where rn > 1
Another option GROUP BY, HAVING and INNER JOIN
SELECT
*
FROM
Tbl A INNER JOIN
(
SELECT
CompanyID,
CompanyServiceID
FROM
Tbl
GROUP BY
CompanyID,
CompanyServiceID
HAVING COUNT(1) > 1
) B ON A.CompanyID = B.CompanyID AND
A.CompanyServiceID = B.CompanyServiceID
Using Join..
Select *
from
Yourtable t1
join
(
select companyid,companyserviceid,count(*)
from
Yourtable
having count(*)>1)b
on b.companyid=t1.companyid
and b.companyserviceid=t1.companyserviceid

SQL Select highest values from table on two (or more) columns

not sure if there's an elegant way to acheive this:
Data
ID Ver recID (loads more columns of stuff)
1 1 1
2 2 1
3 3 1
4 1 2
5 1 3
6 2 3
So, we have ID as the Primary Key, the Ver as the version and recID as a record ID (an arbitary base ID to tie all the versions together).
So I'd like to select from the following data, rows 3, 4 and 6. i.e. the highest version for a given record ID.
Is there a way to do this with one SQL query? Or would I need to do a SELECT DISTINCT on the record ID, then a seperate query to get the highest value? Or pull the lot into the application and filter from there?
A GROUP BY would be sufficient to get each maximum version for every recID.
SELECT Ver = MAX(Ver), recID
FROM YourTable
GROUP BY
recID
If you also need the corresponding ID, you can wrap this into a subselect
SELECT yt.*
FROM Yourtable yt
INNER JOIN (
SELECT Ver = MAX(Ver), recID
FROM YourTable
GROUP BY
recID
) ytm ON ytm.Ver = yt.Ver AND ytm.recID = yt.RecID
or, depending on the SQL Server version you are using, use ROW_NUMBER
SELECT *
FROM (
SELECT ID, Ver, recID
, rn = ROW_NUMBER() OVER (PARTITION BY recID ORDER BY Ver DESC)
FROM YourTable
) yt
WHERE yt.rn = 1
Getting maximum ver for a given recID is easy. To get the ID, you need to join on a nested query that gets these maximums:
select ID, ver, recID from table x
inner join
(select max(ver) as ver, recID
from table
group by recID) y
on x.ver = y.ver and x.recID = y.recID
You could use a cte with ROW_NUMBER function:
WITH cte AS(
SELECT ID, Ver, recID
, ROW_NUMBER()OVER(PARTITION BY recID ORDER BY Ver DESC)as RowNum
FROM data
)
SELECT ID,Ver,recID FROM cte
WHERE RowNum = 1
straighforward example using a subquery:
SELECT a.*
FROM tab a
WHERE ver = (
SELECT max(ver)
FROM tab b
WHERE b.recId = a.recId
)
(Note: this assumes that the combination of (recId, ver) is unique. Typically there would be a primary key or unique constraint on those columns, in that order, and then that index can be used to optimize this query)
This works on almost all RDBMS-es, although the correlated subquery might not be handled very efficiently (depending on RDBMS). SHould work fine in MS SQL 2008 though.