How to replace a NULL value in SQL table? - sql

I have a table dbo.People in a database and one of the columns is Name. Some of the fields however are missing a Name value. So I am trying to replace the empty field with No Name. There is also an ID column with values 1, 2, 3, 4, and so on.
What I have so far:
SELECT ISNULL(Name, 'No Name') FROM dbo.People;
I then want to group and count how many times that name occurs
SELECT COUNT(ID), Name
FROM dbo.People
GROUP BY Name;
This works, however my result still shows a blank value with how many times that blank value occurs, rather than No Name.

I realised thanks to Squirrel and other commenters that the way I was typing the query was making it two separate queries.
The correct way I found was to combine them into one:
SELECT COUNT(ID), ISNULL(Name, 'No Name')
FROM dbo.People
GROUP BY Name;

use case when
select sum(case when name='No Name' then 1 else 0 end) as cnt,name from
(
SELECT coalesce(Name, 'No Name' ) as name
FROM dbo.People
) t group by name

Do you only want to get the NULL occurences?
No need to overcomplicate things then, just remember that you cannot compare against a lack of value/data but you can check for it.
SELECT Count(ID)
FROM dbo.People
WHERE Name IS NULL

Related

How to search multiple values in a column with contains?

I have a list with searchitems:
DROP TABLE IF EXISTS #searchitems
SELECT 'Road' as item
INTO #searchitems
UNION
SELECT 'Bike'
item
Road
Bike
And I want looking for rows that contain that items
I put a Full Text Index on the Name column and I tried this already
SELECT Name
FROM [AdventureWorksLT2019].[SalesLT].[Product]
WHERE CONTAINS(*, (Select item FROM #searchitems) )
But it does not work. With just one value its working but not with a list of search values.
Does it even possible with CONTAINS on a SQL-Server.
I expect something like this:
SELECT distinct Name
FROM [AdventureWorksLT2019].[SalesLT].[Product]
WHERE CONTAINS(*, 'Road OR Bike' )
expected output, but why its not working on a input list
Refere the documentation https://learn.microsoft.com/fr-fr/sql/t-sql/queries/contains-transact-sql?view=sql-server-ver16
SELECT distinct Name
FROM [AdventureWorksLT2019].[SalesLT].[Product]
WHERE CONTAINS(*, 'Road OR Bike' )
Is working, official example:
SELECT Name
FROM Production.Product
WHERE CONTAINS(Name, ' Mountain OR Road ')
Update
maybe that's your solution :
SELECT Name
FROM [AdventureWorksLT2019].[SalesLT].[Product]
WHERE CONTAINS(*, (Select STRING_AGG(item, ' OR ') FROM #searchitems)
One way is to use a CTE and JOIN it to your table with LIKE:
WITH searchitems AS
(SELECT 'Road' AS item
UNION ALL
SELECT 'Bike')
SELECT DISTINCT y.name
FROM yourtable y
JOIN searchitems s
ON y.name LIKE CONCAT('%',s.item,'%');
In the CTE, you can select as many items as desired.
You should generally note that lots of LIKE conditions can slow down your query if your table holds very many entries (and of course, similar ideas like CONTAINS can be very slow, too).
This should be avoided if possible and be replaced with an exact string search to improve the execution time.
Then of course the way shown above is no more required, you could just use a standard IN clause:
SELECT name
FROM yourtable
WHERE
name IN ('Road','Bike','Hello World','Another Text');
Try out with some sample data: db<>fiddle

SQL - Where clause with case statement and wildcards

I'm working in Oracle's APEX environment, trying to return all values in one case and specific values in another case. If you aren't familiar with APEX, it uses low-code to produce a front-end page that is data driven; this case uses a dropdown to select from a list, and I'm comparing that list selection to values pulled from my database.
This creates the dropdown list (requires 2 columns - a display column [name], and a return column [id]):
select distinct 'All users' as name,
'99999' as id
from real_table
union
select distinct name,
id
from real_table
That input is stored in a variable we'll call :LIST_INPUT. I want to select all values from another_table when 'All users' is selected, and only those associated with the particular user when their name/id is selected. Below is the code I have to try and achieve that, but no dice.
select name,
id,
other_col1,
other_col2
from another_table
where case
when :LIST_INPUT like '99999' then '%'
else :LIST_INPUT
end like id
This works fine when a real user id is selected, but returns nothing when the 'All users' value is selected. My logic here is that I'm asking it to compare a wildcard to the ID field, so it should return everything, but instead it returns nothing.
Thanks!
Probably case statement is not necesasary, look:
select name,
id,
other_col1,
other_col2
from another_table
where id = :LIST_INPUT
OR :LIST_INPUT like '99999' -- You can use any other condition here
I think your LIKE operator has the operands in the wrong order. Shouldn't it be?
select name,
id,
other_col1,
other_col2
from another_table
where id like case
when :LIST_INPUT like '99999' then '%'
else :LIST_INPUT
end

How do I combine columns into one, and filter out NULLs?

Here is my table. A list of ids with signup dates in columns newsletter, report, infographics.
I want to combine all those columns into one, without the NULLs
I've tried the following code
SELECT id, combined_column
FROM (
SELECT id, CONCAT(newsletter, report, infographics) AS combined_column
FROM table
)
WHERE combined_column IS NOT NULL
But this just gives me a blank table. Is there a way to solve this? Thanks
I think you want coalesce which return the first not null value from the list (it you have more than one not null value in a row it'll still return the first one):
SELECT id, COALESCE(newsletter, report, infographics) AS combined_date
FROM t
WHERE COALESCE(newsletter, report, infographics) IS NOT NULL
Do you just want this?
select max(newsletter) as newsletter,
max(report) as report,
max(infographics) as infographics
from t;
Answer may depend on what database you're using, so caveat lector.
Is it the case that only one column will be non-null, as in your sample?
Then something like:
SELECT id, COALESCE(newsletter, infographics, report) FROM my_table;
might work for you...
If you are using Oracle, use NVL to replace NULL with empty string
SELECT id,
combined_column
FROM (
SELECT id,
CONCAT(NVL(newsletter,''), NVL(report,''), NVL(infographics,'')) AS combined_column
FROM table
)
WHERE combined_column is not NULL
SELECT id,
CONCAT(newsletter, report, infographics) AS combined_column
FROM table WHERE newsletter is NOT NULL and report is NOT NULL and infographics is NOT NULL

Query to write extra rows in Excel output

I'm trying to accomplish something that seems like it should be straightforward in MS Excel. I want to use a single SQL query - so I can pass it on to others to copy and paste - though I know the following could be achieved with other methods as well. Sheet 1 looks like this:
ID value value_type
1 minneapolis city_name
2 cincinnati city_name
I want an SQL query to return an "exploded" version of those two rows:
ID attr_name attr_value
1 value minneapolis
1 value_type city_name
2 value cincinnati
2 value_type city_name
There's much more I need to do, but this concept gets at the heart of the issue. I've tried a single SELECT statement, but can't seem to make it create two rows from one, and when I tried using UNION ALL I got a syntax error.
In Microsoft Query, how can I construct an SQL statement to create two rows from the existing values in one row?
UPDATE
thanks for the help so far. First, for reference, here is the default statement that recreates the table in Microsoft Query:
SELECT
`Sheet3$`.ID,
`Sheet3$`.name,
`Sheet3$`.name_type
FROM `path\testconvert.xlsx`.`Sheet3$` `Sheet3$`
So, following #lad2025's lead, I have:
SELECT
ID = `Sheet3$`.ID
,attr_name = 'value'
,attr_value = `Sheet3$`.value
FROM `path\testconvert.xlsx`.`Sheet3$` `Sheet3$`
UNION ALL
SELECT
ID = `Sheet3$`.ID
,attr_name = 'value_type'
,attr_value = `Sheet3$`.value_type
FROM `path\testconvert.xlsx`.`Sheet3$` `Sheet3$`
And the result is this error Too few parameters. Expected 4.
LiveDemo
CREATE TABLE #mytable(
ID INTEGER NOT NULL PRIMARY KEY
,value VARCHAR(11) NOT NULL
,value_type VARCHAR(9) NOT NULL
);
INSERT INTO #mytable(ID,value,value_type) VALUES (1,'minneapolis','city_name');
INSERT INTO #mytable(ID,value,value_type) VALUES (2,'cincinnati','city_name');
SELECT
ID
,[attr_name] = 'value'
,[attr_value] = value
FROM #mytable
UNION ALL
SELECT
ID
,[attr_name] = 'value_type'
,[attr_value] = value_type
FROM #mytable
ORDER BY id;
Ok, after going back to the original statement and working up from there as per the suggestions from #lad2025, I've come up with this statement which achieves what I was looking for in my original question:
SELECT
ID,
'name' AS [attr_name],
name AS [attr_value]
FROM `path\testconvert.xlsx`.`Sheet3$` `Sheet3$`
UNION ALL
SELECT
ID,
'name_type',
name_type
FROM `path\testconvert.xlsx`.`Sheet3$` `Sheet3$`
ORDER BY ID;
One of the main problems is that the new column names are only defined in the first SELECT statement. Also, brackets are ok, just not how #lad2025 was using them originally.
Microsoft Query is pretty finicky.

Updating earliest record in SQL?

I have a problem at the moment where I would like to update the earliest entry for a job in my table called Service_Log_Temp with duplicate = 'No' and the rest with duplicate = 'Yes'
Here is my table at the moment:
So I would like a script which looks at the K_B_Job_No (you'll see I have 2 different jobs listed here) and updates the earliest entry based on L1_GA_SR_Creation_Date & L2_B_Start_time_Of_Activity with Duplicate = 'No' and the rest with Duplicate = 'Yes'.
This is how it should look:
Any ideas?
try this
select key_service,k_r_job_no,L1_GA_SR_Creation_Date,L2_B_Start_time_Of_Activity,
case
when (select min(L1_GA_SR_Creation_Date) and min(L2_B_Start_time_Of_Activity)
then 'No'
else 'Yes'
end as Duplicate
from Service_Log_Temp
group by k_r_job_no
;with a as (select K_B_Job_No, min(L1_GA_SR_Creation_Date + cast(L2_B_Start_time_Of_Activity as datetime)) as dttime from Service_Log_Temp
group by K_B_Job_No)
select key_service,K_B_Job_No,L1_GA_SR_Creation_Date,L2_B_Start_time_Of_Activity,
(case when
(select dttime from a where a.K_B_Job_No=b.K_B_Job_No)=(L1_GA_SR_Creation_Date + cast(L2_B_Start_time_Of_Activity as datetime))
then 'NO' else 'YES' end) as Duplicate
from Service_Log_Temp b
this should work in postgres, where the concatenation is || - you must change that to whatever is the concatenation in your system
background: To find the time for the first run of each job :
select k_r_job_no,min( L1_GA_SR_Creation_Date+L2_B_Start_time_Of_Activity) from
service_log_temp
group by k_r_job_no
The problem is just that we cannot get the ids out from this query...
but we can use this as a subquery. As it is normally not possible to get more than one row out of a subquery, we have to do a concatenation to get the right time for each job: (you may need to do a type cast to get the concatenation to work)
select key_service from service_log_temp where
k_r_job_no||L1_GA_SR_Creation_Date+L2_B_Start_time_Of_Activity in(
select k_r_job_no||min( L1_GA_SR_Creation_Date+L2_B_Start_time_Of_Activity)
from service_log_temp
group by k_r_job_no
)
This can be rewritten as an update:
update service_log_temp set Duplicate='Yes' where
k_r_job_no||L1_GA_SR_Creation_Date+L2_B_Start_time_Of_Activity in(
select k_r_job_no||min( L1_GA_SR_Creation_Date+L2_B_Start_time_Of_Activity)
from service_log_temp
group by k_r_job_no
)
And then afterwards
update service_log_temp set Duplicate='No' where Duplicate is null
(or, use "case" as SRIRAM proposed if you want to have it in one query)