Say I have the following:
CREATE TABLE newtable AS (
SELECT #rownum:=#rownum+1 as rownum, name, age FROM (
SELECT name, age FROM clubAmembers
UNION
SELECT name, age FROM clubBmembers
)
) AS atable
How can I make it such that I can "stick in a new row at the beginning of the table" prior to the SELECT union such that it would start with:
rownum | name| age
1 | "Jordan" | 6 <-- This is an arbitrarily inserted record with name="Jordan" age="6" that is not a part of any of the clubAmembers or clubBmembers table.
The rest of the table (rownum 2 and onwards) would contain the actual result form the union with clubAmembers then clubBmembers.
Basically I am looking for:
CREATE TABLE
INSERT a row "Jordan" | 6
Perform select with union such that the rows after the first would start with "rownum=2", all the data from clubAmembers, etc.
How to best do this?
"At the beginning of the table" is not truly meaningful to relational databases because the order results are returned are not guaranteed until you use an ORDER BY clause, at which point the order on disk becomes a moot point anyway.
In your case, since you want to guarantee an order in your result clause (and therefore ordering #rownum, you will have to use ORDER BY. Something like:
CREATE TABLE newtable AS (
SELECT #rownum:=#rownum+1 as rownum, name, age
FROM (
SELECT 'Jordan' AS name, 6 AS age, 0 AS ord
UNION
SELECT name, age, 1 AS ord FROM clubAmembers
UNION
SELECT name, age, 1 AS ord FROM clubBmembers
ORDER BY ord
)
) AS atable
Note that at no point does this guarantee that rows in clubAmembers will have a lower rownum than rows in clubBmembers. If you want to guarantee that clubAmembers have a lower rownum, while keeping the semantics of UNION (versus UNION ALL), you can use the following:
CREATE TABLE newtable AS (
SELECT #rownum:=#rownum+1 as rownum, name, age
FROM (
SELECT 'Jordan' AS name, 6 AS age, 0 AS ord
UNION ALL
SELECT name, age, 1 AS ord FROM clubAmembers
UNION ALL
SELECT name, age, 2 AS ord FROM clubBmembers AS b
WHERE NOT EXISTS(SELECT 1 FROM clubAmembers AS a
WHERE a.name = b.name AND a.age = b.age)
ORDER BY ord
)
) AS atable
Note if {name, age} could be duplicated within the clubXmembers table, you will need to add DISTINCT:
...
SELECT DISTINCT name, age, 1 AS ord FROM clubAmembers
UNION ALL
...
As per the request in the comments, if you had a clubCmembers table, you would do:
CREATE TABLE newtable AS (
SELECT #rownum:=#rownum+1 as rownum, name, age
FROM (
SELECT 'Jordan' AS name, 6 AS age, 0 AS ord
UNION ALL
SELECT name, age, 1 AS ord FROM clubAmembers
UNION ALL
SELECT name, age, 2 AS ord FROM clubBmembers AS b
WHERE NOT EXISTS(SELECT 1 FROM clubAmembers AS a
WHERE a.name = b.name AND a.age = b.age)
SELECT name, age, 3 AS ord FROM clubCmembers AS c
WHERE NOT EXISTS(SELECT 1 FROM clubAmembers AS a
WHERE a.name = c.name AND a.age = c.age)
AND NOT EXISTS(SELECT 1 FROM clubBmembers AS b
WHERE b.name = c.name AND b.age = c.age)
ORDER BY ord
)
) AS atable
I'm not sure if I got it right. But why don't you just add another union like this:
CREATE TABLE newtable AS (
SELECT #rownum:=#rownum+1 as rownum, name, age FROM (
SELECT 1, "Jordan", 6
UNION ALL
SELECT name, age FROM clubAmembers
UNION ALL
SELECT name, age FROM clubBmembers
)
) AS atable
You can separate the create table statmenet from the insert statmenet:
Create the table (you must know which colums are gona be there)
Insert your 1st record (INSERT INTO .... Values(...))
Use your statement but with insert into instead of create table like: INSERT INTO YourNewTable.... Values(YourSubQuery) (Nr and tye of columns must match your subquery)
This should do, I believe:
CREATE TABLE newtable AS (
SELECT (#rownum:=IFNULL(#rownum,0)+1)+1 as rownum, name, age FROM (
SELECT name, age FROM clubAmembers
UNION
SELECT name, age FROM clubBmembers
) AS s
UNION ALL
SELECT 1, 'Jordan', 6
) AS atable
Demo at SQL Fiddle: http://sqlfiddle.com/#!2/ab825/6
Related
let say we have a table with below column details.
now I wanted to extract only those custID's where either SSN or DL number is same for different custid
table
***CustID SSN DL***
1111 112331 DL1234
1112 113096 DL0987
1113 113861 DL1234
1114 112331 DL2315
1115 111104 DL5443
1115 111104 DL5443
in this I only want 1111,1113 & 1114
enter image description here
In Oracle, you can do it in a single table scan using analytic functions:
SELECT CustID
FROM (
SELECT CustID,
COUNT(*) OVER (PARTITION BY SSN, DL) AS num_ssl_dn,
COUNT(*) OVER (PARTITION BY SSN) AS num_ssn,
COUNT(*) OVER (PARTITION BY DL) AS num_dl
FROM table_name
)
WHERE num_ssn > num_ssl_dn
OR num_dl > num_ssl_dn;
Which, for the sample data:
CREATE TABLE table_name ( CustID, SSN, DL ) AS
SELECT 1111, 112331, 'DL1234' FROM DUAL UNION ALL
SELECT 1112, 113096, 'DL0987' FROM DUAL UNION ALL
SELECT 1113, 113861, 'DL1234' FROM DUAL UNION ALL
SELECT 1114, 112331, 'DL2315' FROM DUAL UNION ALL
SELECT 1115, 111104, 'DL5443' FROM DUAL UNION ALL
SELECT 1115, 111104, 'DL5443' FROM DUAL;
Outputs:
CUSTID
1111
1114
1113
sqlfiddle here
You can use exists:
select t.*
from t
where exists (select 1
from t t2
where t2.ssn = t.ssn and t2.custid <> t.custid
) or
exists (select 1
from t t2
where t2.dl = t.dl and t2.custid <> t.custid
) ;
This intentionally uses two exists instead of or in a single subquery so the optimizer can use indexes on (ssn) and (dl) if available.
Assuming the table name is table_name, you can do it like this:
select custid
from (
select custid,
count(distinct custid) over (partition by ssn) ssn_ct,
count(distinct custid) over (partition by dl) dl_ct
from table_name
)
where ssn_ct > 1 or dl_ct > 1
;
Good day i would like to ask if this is possible in MySQL
SELECT id,label,name,age,sex FROM table LIMIT 3
Output
[row1] id,label,name,age,sex
[row2] id,label,name,age,sex
[row3] id,label,name,age,sex
My Output Needed
[row1] id
[row2] label
[row3] name
[row4] age
[row5] sex
[row6] id
[row7] label
[row8] name
[row9] age
[row10] sex
[row11] id
[row12] label
[row13] name
[row14] age
[row15] sex
You can do something like this:
SELECT * FROM
((SELECT id AS id1, 1 AS rownum, 'id' AS colname, id AS Data_value FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 2, 'label', label FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 3, 'name', name FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 4, 'age', age FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 5, 'sex', sex FROM mytable LIMIT 3)) A
ORDER BY id1, rownum
Here's a fiddle: https://www.db-fiddle.com/f/dvg6x1vBg6H5bDNp9VZxQa/4
I've added 3 additional column id AS id1, rownum and colname. The first two additional column is used for ORDER BY at the outer query. If you don't want to see the additional column, you can just type SELECT Data_value FROM ... at the outer query.
You can use group_concat() to aggregate rows by string concatenation. For the LIMIT to work you then need to use a derived table. But you should be careful with a LIMIT without an ORDER BY. As the order of a query result can be random unless an explicit ORDER BY is issued, you may get different results each time you run the query.
SELECT group_concat(id,
'\n',
label,
'\n',
name,
'\n',
age,
'\n',
sex
SEPARATOR '\n')
FROM (SELECT id,
label,
name,
age,
sex
FROM elbat
LIMIT 3) x;
If you just want to concatenate the columns but keep the rows just use concat().
SELECT concat(id,
'\n',
label,
'\n',
name,
'\n',
age,
'\n',
sex)
FROM elbat
LIMIT 3;
yes,you can use union all like below :
SELECT id FROM table LIMIT 3
union all
SELECT label FROM table LIMIT 3
union all
SELECT name FROM table LIMIT 3
union all
SELECT age FROM table LIMIT 3
union all
SELECT sex FROM table LIMIT 3
That what you looking is to Unpivot data. For more info about pivot and unpivot you can check here.
http://archive.oreilly.com/oreillyschool/courses/dba1/dba110.html
Unfortunately there is no easy way to unpivot in mysql.
The below script will work for MySQL 8.0
set #rowNum :=0;
set #string :=(
select group_concat(id,',',label,',',name,',',age,',',sex separator ',')
from (
select id, label, name, age, sex from mytable limit 3
) x
);
with recursive
R1 as ( select #string as items),
R2 as ( select 1 as n
union
select n + 1 from R2, R1
where n <= length(items) - length(replace(items, ',', '')))
select distinct #rowNum := #rowNum+1 as rowNum, substring_index(substring_index(items, ',', n), ',', -1) output from R2, R1;
Suppose I've Table T and It has 3 Columns and 3rd Column contains 10 distinct values and I want to fetch 5 samples from Table T for each distinct value in column 3rd.
WITH T(A, B,C) AS(
SELECT 12,'Hi','One' FROM DUAL UNION ALL
SELECT 34,'Am','One' FROM DUAL UNION ALL
SELECT 6,'to','Two' FROM DUAL UNION ALL
SELECT 3,'do','Two' FROM DUAL UNION ALL
SELECT 5,'aim','Two' FROM DUAL UNION ALL
SELECT 6,'mine','Two' FROM DUAL UNION ALL
SELECT 4,'not','Three' FROM DUAL
)
select a,b,c from(
SELECT A,B,C,ROW_NUMBER() OVER(PARTITION BY c ORDER BY C DESC) AS R
FROM T)
where r = 1
or you could possibly try this:
SELECT MIN(T.A),
T.B,
t.c
FROM t
JOIN (SELECT C,
MAX(b) AS b
FROM T
GROUP BY C) Y ON Y.C = T.C
AND Y.B = T.B
GROUP BY t.c, t.b
For example:
pk_ref fk
====== ===
1 a
1 b
1 c
2 a
2 b
2 d
How do I do a query like the "pseudo" query:
select distinc pk_ref
where fk in all('a', 'c');
The return query result must match all given values for the foreign key in the list.
The result should be:
1
While the following select must not return any records.
select distinc pk_ref
where fk in all('a', 'c', 'd');
How do I do that?
Try this
select pk_ref
from yourtable
group by pk_ref
having count(case when fk = 'a', then 1 end) >= 1
and count(case when fk = 'c' then 1 end) >= 1
To do it dynamically. (considering you are using SQL SERVER)
Create a split string function and pass the input as comma separated values
Declare #input varchar(8000)= 'a,c',#cnt int
set #cnt = len(#input)-len(replace(#input,',','')) + 1
select pk_ref
from yourtable
Where fk in (select split_values from udf_splitstring(#input , ','))
group by pk_ref
having count(Distinct fk) >= #cnt
You can create a split string function from the below link
https://sqlperformance.com/2012/07/t-sql-queries/split-strings
:list is the input list (bind variable). The difference of length() return values is the number of commas in the bind variable. This query, or something very close to it, should work in pretty much any DB product. Tested in Oracle.
select pk_ref
from tbl -- enter your table name here
where ',' || :list || ',' like '%,' || fk || ',%'
group by pk_ref
having count(distinct fk) = 1 + length(:list) - length(replace(:list, ',', ''))
If you can pass the IN operator values as Set, then you can do this as below
Schema:
SELECT * INTO #TAB FROM (
SELECT 1 ID, 'a' FK
UNION ALL
SELECT 1, 'b'
UNION ALL
SELECT 1, 'c'
UNION ALL
SELECT 2, 'a'
UNION ALL
SELECT 2, 'b'
UNION ALL
SELECT 2, 'd'
UNION ALL
SELECT 1, 'a'
)AS A
Used CTE to make 'a','c' as Set
;WITH CTE AS (
SELECT 'a' FK --Here 'a','c' passed as a Set through CTE
UNION
SELECT 'c'
)
,FINAL AS(
SELECT DENSE_RANK() OVER (PARTITION BY ID ORDER BY (FK))AS COUNT_ID, ID, FK
FROM #TAB where FK IN (select FK FROM CTE)
)
SELECT ID FROM FINAL WHERE COUNT_ID>=(SELECT COUNT( FK) FROM CTE)
Select pk_ref where fk='a' and pk_ref in (select pk_ref where fk='c' from yourtable) from yourtable;
or
select pk_ref where fk='a' from yourtable intersect select pk_ref where fk='c' from yourtable;
DECLARE #inputVariable VARCHAR(200) = 'a,b,c,d'
DECLARE #inputValue INT
DECLARE #tblInput TABLE
(
FK VARCHAR(100)
)
INSERT INTO #tblInput
SELECT SUBSTRING( #inputVariable+',',RN,1)
FROM (SELECT TOP 100 ROW_NUMBER() OVER(ORDER BY s.object_id) RN
FROM sys.objects s) s
where LEN(#inputVariable) >= RN
AND SUBSTRING(','+ #inputVariable,RN,1) = ','
SELECT #inputValue = COUNT(1) FROm #tblInput
--#inputVariable
DECLARE #tbl TABLE
(
ID INT,
FK VARCHAR(100)
)
INSERT INTO #tbl
SELECT 1 ID, 'a' FK
UNION ALL
SELECT 1, 'b'
UNION ALL
SELECT 1, 'c'
UNION ALL
SELECT 2, 'a'
UNION ALL
SELECT 2, 'b'
UNION ALL
SELECT 2, 'd'
UNION ALL
SELECT 1, 'a'
SELECT t.ID ,COUNT(DISTINCT t.FK)
FROM #tbl t
INNER JOIn #tblInput ti
ON t.FK = ti.FK
GROUP BY ID
HAVING COUNT(DISTINCT t.FK) = #inputValue
I want to find out the longest sequence of letter in a string
e.g. in the word Honorificabcdwert , the output will be abcd.
How can I do it?
My idea is to get the Ascii and then count the sequence until it breaks at some point. But I was able to proceed with only
DECLARE #t TABLE(ID INT IDENTITY,String VARCHAR(100))
INSERT INTO #t SELECT 'Honorificabcdwert'
;with Get_Individual_Chars_Cte AS
(
SELECT
ID
,Row_ID =ROW_NUMBER() Over(PARTITION by ID Order by ID)
,SUBSTRING(String,Number,1) AS [Char]
,ASCII(SUBSTRING(String,Number,1)) AS [Ascii Value]
FROM #t
INNER JOIN master.dbo.spt_values ON
Number BETWEEN 1 AND LEN(String)
AND type='P'
)
Select * from Get_Individual_Chars_Cte
After this I don't know what to do. Help needed for this or any other way of doing so.
Will this help
DECLARE #t TABLE(ID INT IDENTITY,String VARCHAR(100))
INSERT INTO #t
SELECT 'Honorificabcdwert' UNION ALL
SELECT 'AbCdEfxy' UNION ALL
SELECT 'abc1234defg' UNION ALL
SELECT 'XYZABCPPCKLMIDBABC' UNION ALL
SELECT 'MNOP$%^&~()MNOPQRS;:'
SELECT ID, OriginalString,Sequence
FROM (SELECT ID, REPLACE(string,'%','') AS Sequence,OriginalString,
ROW_NUMBER() OVER(PARTITION BY ID ORDER BY LEN(string) DESC, string) AS rn
FROM (SELECT OriginalString = b.String, CASE WHEN b.String LIKE a.strings THEN a.strings ELSE NULL END AS string,
b.ID, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY LEN(strings) DESC, strings) AS rn
FROM (SELECT COALESCE('%' + b.strings+a.strings + '%','%' + a.strings + '%') AS strings
FROM (SELECT SUBSTRING('ABCDEFGHIJKLMNOPQRSTUVWXYZ',t1.N,t2.N-t1.N+1) AS strings, t1.N
FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),
(9),(10),(11),(12),(13),(14),(15),
(16),(17),(18),(19),(20),(21),(22),
(23),(24),(25),(26)) t1(N)
CROSS JOIN (VALUES(1),(2),(3),(4),(5),(6),(7),(8),
(9),(10),(11),(12),(13),(14),(15),
(16),(17),(18),(19),(20),(21),(22),
(23),(24),(25),(26)) t2(N)
WHERE t1.N <= t2.N) a
LEFT OUTER JOIN (SELECT REVERSE(SUBSTRING('ZYXWVUTSRQPONMLKJIHGFEDCBA',1,N)) AS strings, 1 AS ID
FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),
(9),(10),(11),(12),(13),(14),(15),
(16),(17),(18),(19),(20),(21),(22),
(23),(24),(25),(26)) t1(N)
UNION ALL SELECT '', 1) b ON a.N = b.ID) a
CROSS JOIN #t b) a ) a
WHERE a.rn = 1
ORDER BY a.ID
Result
ID OriginalString Sequence
1 Honorificabcdwert ABCD
2 AbCdEfxy ABCDEF
3 abc1234defg DEFG
4 XYZABCPPCKLMIDBABC XYZABC
5 MNOP$%^&~()MNOPQRS;: MNOPQRS
Based on your inputs provided in the course of discussion with #Martin Smith, the program is being developed. Please test it and let me know if it satisfies your requirement.
For consecutive rows with characters rising in alphabetical order (equating alphabetical order with ASCII order here) ROW_NUMBER() OVER (ORDER BY Row_ID) - [Ascii Value] will be the same.
This is not sufficient on its own however as for the string ABCZE that would put E in the same group as ABC so then you need a second operation to find gaps in that grouping sequence.
Something like the following should do it.
DECLARE #t TABLE(ID INT IDENTITY,String VARCHAR(100))
INSERT INTO #t SELECT 'Honorificabcdwfrt'
;with Get_Individual_Chars_Cte AS
(
SELECT
ID
,Row_ID =ROW_NUMBER() Over(PARTITION by ID Order by ID)
,SUBSTRING(String,number,1) AS [Char]
,ASCII(SUBSTRING(String,number,1)) AS [Ascii Value]
FROM #t
INNER JOIN master.dbo.spt_values ON
number BETWEEN 1 AND LEN(String)
AND type='P'
)
, T1 AS
(
Select *,
ROW_NUMBER() OVER (ORDER BY Row_ID) - [Ascii Value] AS RN
from Get_Individual_Chars_Cte
), T2 AS
(
SELECT *,
ROW_NUMBER() OVER (ORDER BY Row_ID) -
ROW_NUMBER() OVER (PARTITION BY RN ORDER BY Row_ID) AS Grp
FROM T1
)
SELECT TOP 1 WITH TIES *
FROM T2
ORDER BY COUNT(*) OVER (PARTITION BY RN, Grp) DESC