How to find the count of empty space expressions in column values? - sql

if you have
e_id ename
1 hansen sahul
2 dennis richard rathore
how to find the ename count of e_id 1 as ? 2
how to find the ename count of e_id 2 as ? 3

Unfortunately, the string manipulation functions vary between databases, so I can give SQL Server dialect. If you're using a different database, you'll have to find the replacements for LEN and REPLACE:
declare #Names table (e_id int,ename varchar(3000))
insert into #Names (e_id, ename) values
(1,'hansen sahul'),
(2,'dennis richard rathore')
select e_id,LEN(ename) - LEN(REPLACE(ename,' ','')) + 1 as namecount
from #Names
Result:
e_id namecount
----------- -----------
1 2
2 3
This works be calculating the difference in length between the plain string, and the same string where spaces have been removed. This is logically equivalent to the number of spaces in the string. We then add 1 to match your desired result (the number of names, rather than the number of spaces).
(The table setup is also dialect, but just there to help create a working script)

Related

First name should randomly match with other FIRST name

All first name should randomly match with each other and when I tried to run query again the First Name should be match with others name. Not the match with FIRST time match.
For example I have 6 records in one table ...
First name column looks like:
JHON
LEE
SAM
HARRY
JIM
KRUK
So I want result like
First name1 First name2
Jhon. Harry
LEE. KRUK
HARRY SAM
The simplest solution is to first randomly sort the records, then calculate the grouping and a sequence number within the group and then finally select out the groups as rows.
You can follow along with the logic in this fiddle: https://dbfiddle.uk/9JlK59w4
DECLARE #Sorted TABLE
(
Id INT PRIMARY KEY,
FirstName varchar(30),
RowNum INT IDENTITY(1,1)
);
INSERT INTO #Sorted (Id, FirstName)
SELECT Id, FirstName
FROM People
ORDER BY NEWID();
WITH Pairs as
(
SELECT *
, (RowNum+1)/2 as PairNum
, RowNum % 2 as Ordinal
FROM #Sorted
)
SELECT
Person1.FirstName as [First name1], Person2.FirstName as [First name2]
FROM Pairs Person1
LEFT JOIN Pairs Person2 ON Person1.PairNum = Person2.PairNum AND Person2.Ordinal = 1
WHERE Person1.Ordinal = 0
ORDER BY Person1.PairNum
ORDER BY NEWID() is used here to randomly sort the records. Note that it is indeterminate and will return a new value with each execution. It's not very efficient, but is suitable for our requirement.
You can't easily use CTE's for producing lists of randomly sorted records because the result of a CTE is not cached. Each time the CTE is referenced in the subsequent logic can result in re-evaluating the expression. Run this fiddle a few times and watch how it often allocates the names incorrectly: https://dbfiddle.uk/rpPdkkAG
Due to the volatility of NEWID() this example stores the results in a table valued variable. For a very large list of records a temporary table might be more efficient.
PairNum uses the simple divide by n logic to assign a group number with a length of n
It is necessary to add 1 to the RowNum because the integer math will round down, see this in action in the fiddle.
Ordinal uses the modulo on the RowNumber and is a value we can use to differentiate between Person 1 and Person 2 in the pair. This helps us keep the rest of the logic determinate.
In the final SELECT we select first from the Pairs that have an Ordinal of 0, then we join on the Pairs that have an Ordinal of 1 matching by the PairNum
You can see in the fiddle I added a solution using groups of 3 to show how this can be easily extended to larger groupings.

Why is this join not working in Oracle SQL

I am trying to output everything for table one where there is a mention like something from table two
table one is the aoldataleak from 2006 and table two is a created table of all contestants in a horse race at that time period
select query,
PFERDENAME
from AOLDATA.querydata,
Pferde
where query like ( '%' ||PFERDENAME||'%')
ORDER BY PFERDENAME;
Pferdename is a column in table 2 and query is a column in table one
both are chars and the output I get is just a blank table, but I know for a fact there are querys in the first table that are like Pferdenamen in the second one.
I tried this same statement with a dummy table with only a few entries and there it worked just fine
So here's error cause:
Pferdename CHAR (25) PRIMARY KEY
CHAR datatype right-pads values with spaces up to the max column length. So, if horse name is "Max", Oracle stores it as "Max" followed by 22 spaces (which alltogether make 3 + 22 = 25 characters).
You shouldn't
use CHAR in such a case; use VARCHAR2 instead
name is not the best choice for a primary key; it means that there can't be two horses whose names are "Max"
If it must be CHAR, then you'd better trim it, e.g.
select query, PFERDENAME
from AOLDATA.querydata, Pferde
where query like ( '%' || trim(PFERDENAME) ||'%')
ORDER BY PFERDENAME;
Example:
SQL> with
2 querydata (query) as
3 (select 'This is Max, my favorite horse' from dual),
4 pferde (pferdename) as
5 (select 'Max ' from dual)
6 select query, pferdename
7 from querydata, pferde
8 where query like ( '%' || trim(pferdename) ||'%')
9 order by pferdename;
QUERY PFERDENAME
------------------------------ -----------
This is Max, my favorite horse Max
SQL>

Find column values where first letter is upper case

I have a table EMP_INFO with EID, ENAME, GENDER. My objective is to display only those ENAME values where the first letter is Capital or uppercase.
Table like:
EID ENAME GENDER
001 Samuel M
002 john M
003 susan F
004 CALEB M
Desired output like:
EID ENAME
001 Samuel
004 CALEB
I have tried:
SELECT EID, ENAME
FROM EMP_INFO
WHERE ENAME like '[A-Z]%';
But this is just giving a blank output. No errors, no warnings but no output as well. Also I am using oracle sql developer.
Oracle does not support wildcards in the LIKE pattern. You can use regular expressions instead:
select EID , ENAME
from EMP_INFO
where regexp_like(ENAME, '^[A-Z]');
Alternatively, you could just compare the first character:
where substr(ENAME, 1, 1) BETWEEN 'A' AND 'Z'
Here is a working example of this version.
By default, Oracle is case-sensitive, so these should work on most Oracle systems.
We have a well-known function called initcap to be considerable :
SELECT EID, ENAME
FROM EMP_INFO
WHERE substr(ENAME,1,1) = substr(initcap(ENAME),1,1);
or alternatively use :
SELECT EID, ENAME
FROM EMP_INFO
WHERE ENAME between chr(65) and chr(92);
SQL Fiddle Demo
You might try something like the following (assuming you've not done anything to make your SQL queries case-insensitive):
SELECT eid, ename
FROM emp_info
WHERE ename >= 'A'
AND ename < CHR(ASCII('Z')+1);
This will ensure that the first character of ename falls between A and Z inclusive. The value of CHR(ASCII('Z')+1) is [ but that's not terribly important - I think it's clearer to use the functions in this case than the "magic character".
EDIT: The reason this works is that lower-case characters, as a group, appear after upper-case characters in many character sets*, so as long as a value of ename is between A and Z inclusive, according to the typical string comparison, it will start with an upper-case character.
*For example, here is the Unicode character table and here is the ASCII character table. I suspect that this solution may not work with EBCDIC character sets but I don't have a server handy on which I can confirm that suspicion.

Oracle Dynamic Pivoting

I have the below table. I need to create columns based off the column CCL. The values in column CCL are unknown. I'm not sure where to begin here. Any help would be appreciated.
TABLEA
ID CCL Flag
1 john x
1 adam x
1 terry
1 rob x
2 john x
Query:
SELECT *
FROM TABLEA
Output:
ID John Adam Terry Rob
1 x x x
2 x
Using dynamic sql for a result where the columns are unknown at the time of executing is a bit of a hassle in Oracle compared to certain other RDMBS.
Because the record type for the output is yet unknown, it can't be defined beforehand.
In Oracle 11g, one way is to use a nameless procedure that generates a temporary table with the pivoted result.
Then select the results from that temporary table.
declare
v_sqlqry clob;
v_cols clob;
begin
-- Generating a string with a list of the unique names
select listagg(''''||CCL||''' as "'||CCL||'"', ', ') within group (order by CCL)
into v_cols
from
(
select distinct CCL
from tableA
);
-- drop the temporary table if it exists
EXECUTE IMMEDIATE 'DROP TABLE tmpPivotTableA';
EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF;
-- A dynamic SQL to create a temporary table
-- based on the results of the pivot
v_sqlqry := '
CREATE GLOBAL TEMPORARY TABLE tmpPivotTableA
ON COMMIT PRESERVE ROWS AS
SELECT *
FROM (SELECT ID, CCL, Flag FROM TableA) src
PIVOT (MAX(Flag) FOR (CCL) IN ('||v_cols||')) pvt';
-- dbms_output.Put_line(v_sqlqry); -- just to check how the sql looks like
execute immediate v_sqlqry;
end;
/
select * from tmpPivotTableA;
Returns:
ID adam john rob terry
-- ---- ---- --- -----
1 x x x
2 x
You can find a test on db<>fiddle here
In Oracle 11g, another cool trick (created by Anton Scheffer) to be used can be found in this blog. But you'll have to add the pivot function for it.
The source code can be found in this zip
After that the SQL can be as simple as this:
select * from
table(pivot('SELECT ID, CCL, Flag FROM TableA'));
You'll find a test on db<>fiddle here
Oracle must know all the column in select list on PARSING stage.
This has a couple of consequences
It's not possible for Oracle to change the column list of the query without re-parsing it. Regardless what is supposed to impact that - whether it's distinct list of values in some column or something else. In other words you cannot expect Oracle to add new columns to output if you added new value to CCL column in your example.
In each and every query you must specify explicitly all the columns in select list unless you use "*" with table alias. If you use "*" then Oracle gets column list from metadata and if you modify metadata (i.e. run DDL on a table) then Oracle re-parses query.
So the best option to deal with "Dynamic Pivoting" is to pivot and format result in the UI. However, there are still some options in database which you may want to consider.
Generating XML with pivoted result and parsing it.
Do pivot for XML and then parse results. In this case, eventually, you have to specify pivoted columns one way or another.
create table tablea(id, ccl, flag) as
(
select 1, 'john', 'x' from dual
union all select 1, 'adam', 'x' from dual
union all select 1, 'terry', null from dual
union all select 1, 'rob', 'x' from dual
union all select 2, 'john', 'x' from dual
);
In below example you do NOT have to provide list of the values for CCL, the only literals you specify are:
pivoted expression (FLAG) and column used for pivoting (CCL).
SQL> select id, x.*
2 from tablea t
3 pivot xml (max(flag) flag for ccl in(any))
4 -- parsing output
5 , xmltable('/PivotSet' passing ccl_xml
6 columns
7 name1 varchar2(30) path '/PivotSet/item[1]/column[#name="CCL"]/text()',
8 value1 varchar2(30) path '/PivotSet/item[1]/column[#name="FLAG"]/text()',
9 name2 varchar2(30) path '/PivotSet/item[2]/column[#name="CCL"]/text()',
10 value2 varchar2(30) path '/PivotSet/item[2]/column[#name="FLAG"]/text()',
11 name3 varchar2(30) path '/PivotSet/item[3]/column[#name="CCL"]/text()',
12 value3 varchar2(30) path '/PivotSet/item[3]/column[#name="FLAG"]/text()',
13 name4 varchar2(30) path '/PivotSet/item[4]/column[#name="CCL"]/text()',
14 value4 varchar2(30) path '/PivotSet/item[4]/column[#name="FLAG"]/text()') x;
ID NAME1 VALUE NAME2 VALUE NAME3 VALUE NAME4 VALUE
---------- ----- ----- ----- ----- ----- ----- ----- -----
1 adam x john x rob x terry
2 john x
You may have noticed 2 important details
In fact, each pivoted column is represented using two columns in result - one for caption and one for value
Names are ordered so you cannot preserver order like in your example ('john', 'adam', 'terry', 'rob'),
moreover one column may represent different names like NAME1 represents values for 'adam' in first row and 'john' in second row.
It's possible to use only indices to get the same output.
select id, x.*
from tablea
pivot xml (max(flag) flag for ccl in(any))
-- parsing output
, xmltable('/PivotSet' passing ccl_xml
columns
name1 varchar2(30) path '/PivotSet/item[1]/column[1]',
value1 varchar2(30) path '/PivotSet/item[1]/column[2]',
name2 varchar2(30) path '/PivotSet/item[2]/column[1]',
value2 varchar2(30) path '/PivotSet/item[2]/column[2]',
name3 varchar2(30) path '/PivotSet/item[3]/column[1]',
value3 varchar2(30) path '/PivotSet/item[3]/column[2]',
name4 varchar2(30) path '/PivotSet/item[4]/column[1]',
value4 varchar2(30) path '/PivotSet/item[4]/column[2]') x;
But still there are two columns for each pivoted column in the output.
Below query returns exactly the same data as in your example
SQL> select id, x.*
2 from tablea
3 pivot xml (max(flag) flag for ccl in(any))
4 -- parsing output
5 , xmltable('/PivotSet' passing ccl_xml
6 columns
7 john varchar2(30) path '/PivotSet/item[column="john"]/column[2]',
8 adam varchar2(30) path '/PivotSet/item[column="adam"]/column[2]',
9 terry varchar2(30) path '/PivotSet/item[column="terry"]/column[2]',
10 rob varchar2(30) path '/PivotSet/item[column="rob"]/column[2]') x;
ID JOHN ADAM TERRY ROB
---------- ----- ----- ----- -----
1 x x x
2 x
But wait... all the values for CCL are specified in the query. This is because column caption cannot depend on the data in the table. So what is the point in pivoting for XML if you could have just hardcoded all values in for clause with the same success? One of the ideas is that Oracle SQL engine transposes query result and the tool which displays output just has to properly parse XML. So you split pivoting logic into two layers. XML parsing can be done outside SQL, say, in your application.
ODCI table interface
There is already a link in another answer to Anton's solution.
You can also check an example here.
And, of course, it's explained in detail in Oracle Documentation.
Polymorphic Table Functions
One more advanced technology has been introduces in Oracle 18 - Polymorphic Table Functions.
But again, you should not expect that column list of your query will change after you added new value to CCL. It can change only after re-parsing. There is a way to force hard parse before each excution, but that is another topic.
Dynamic SQL
Finally, as also already pointed out in the comments, you can use good old DSQL.
First step - generate SQL statement based on the table contents. Second step - execute it.
SQL> var rc refcursor
SQL> declare
2 tmp clob;
3 sql_str clob := 'select * from tablea pivot (max(flag) for ccl in ([dynamic_list]))';
4 begin
5 select listagg('''' || ccl || ''' as ' || ccl, ',') within group(order by max(ccl))
6 into tmp
7 from tablea
8 group by ccl;
9 open :rc for replace(sql_str, '[dynamic_list]', tmp);
10 end;
11 /
PL/SQL procedure successfully completed.
SQL> print rc
ID ADAM JOHN ROB TERRY
---------- ----- ----- ----- -----
1 x x x
2 x

What is the significance of 'ordinals' in an ORDER BY clause with CASE conditions

I have a 'names' tables with two columns: last_name, first_name
last_name first_name
--------- ----------
Basu Rohini
Khan Amartya
Nandy Upanita
Ghosh Shankha
NULL Claire
NULL Amelie
When I am doing (1st SQL):
SELECT last_name, first_name FROM names
ORDER BY
CASE
WHEN last_name IS NOT NULL THEN 3
ELSE 100
END,
last_name DESC
I'm getting an output:
last_name first_name
--------- ----------
Nandy Upanita
Khan Amartya
Ghosh Shankha
Basu Rohini
NULL Amelie
NULL Claire
But when I'm doing this (2nd SQL):
SELECT last_name, first_name from names
ORDER BY
CASE
WHEN last_name IS NOT NULL THEN 3
END,
last_name DESC
Or this (3rd SQL):
SELECT last_name, first_name from names
ORDER BY
CASE
WHEN last_name IS NOT NULL THEN 100
ELSE 3
END,
last_name DESC
I'm getting an output starting with last_name as NULL and first_name in ascending order, followed by the non-null last_names in descending order:
last_name first_name
--------- ----------
NULL Amelie
NULL Claire
Nandy Upanita
Khan Amartya
Ghosh Shankha
Basu Rohini
My questions:
Why is the 1st SQL giving an output with last_name sorted in a descending manner, for non-null last names?
Why I'm not getting an error in 1st SQL for 'CASE WHEN last_name IS NOT NULL THEN 3' saying 'Expressions 3 and last_name in ORDER BY clause are same'?
Why I was able to give any random numbers like 3 and 100, under the CASE statement? As per the SQL standard, this number can only be any non-negative integer value upto the degree of the number of columns. How is the integer within CASE statement working?
Those aren't ordinals - they're just numbers. Each of your CASE expressions essentially boils down to "assign all of the rows with a NULL last name <some fixed value> and all of the non-NULL last name rows <some other fixed value>" and then perform a sort on those fixed values.
So all that these CASE expressions do is ensure that all of the NULL rows will appear before/after the non-NULL rows. The specifics of which way around that is depends on the specific fixed values you're employing in each query.
Why is the 1st SQL giving an output with last_name sorted in a descending manner, for non-null last names?
Because that's what the second expression in your ORDER BY clause asks for?
Why I'm not getting an error in 1st SQL for 'CASE WHEN last_name IS NOT NULL THEN 3' saying 'Expressions 3 and last_name in ORDER BY clause are same'?
Because the expressions aren't the same, and even if they were, SQL doesn't prevent you from asking for redundant/pointless orderings (i.e. you can specify more expressions in an ORDER BY clause than are required to uniquely determine each rows final output position and no error is produced)
Why I was able to give any random numbers like 3 and 100, under the CASE statement? As per the SQL standard, this number can only be any non-negative integer value upto the degree of the number of columns. How is the integer within CASE statement working?
Because, again, these aren't ordinals. In order to be considered an ordinal, you have to supply a constant literal integer as the entire order by expression - not a larger expression, such as these CASE expressions.