Suggestion needed writing a complex query - sqlite - sqlite

I have 4 columns in a table called musics - 'artist','genre', 'writer' , 'producer'.
I need to write a query such that, it returns a value 0 , if there are no repetition of values corresponding to the column name; if there is a repetition of values, it should return a value 1, corresponding to that column name.
Any help is much appreciated

SELECT (COUNT(artist) <> COUNT(DISTINCT artist)) artist,
(COUNT(genre) <> COUNT(DISTINCT genre)) genre,
(COUNT(writer) <> COUNT(DISTINCT writer)) writer,
(COUNT(producer) <> COUNT(DISTINCT producer)) producer
FROM musics
Another version
SELECT
( SELECT (COUNT(*) > 0)
FROM (SELECT 1 FROM musics GROUP BY artist HAVING COUNT(*) > 1) a
) artist,
( SELECT (COUNT(*) > 0)
FROM (SELECT 1 FROM musics GROUP BY genre HAVING COUNT(*) > 1) g
) genre,
( SELECT (COUNT(*) > 0)
FROM (SELECT 1 FROM musics GROUP BY writer HAVING COUNT(*) > 1) w
) writer,
( SELECT (COUNT(*) > 0)
FROM (SELECT 1 FROM musics GROUP BY producer HAVING COUNT(*) > 1) p
) producer
Sample data
| artist | genre | writer | producer |
------------------------------------------
| artist1 | genre1 | writer1 | producer1 |
| artist2 | genre2 | writer1 | producer2 |
| artist1 | genre3 | writer3 | producer3 |
Sample output:
| artist | genre | writer | producer |
--------------------------------------
| 1 | 0 | 1 | 0 |
SQLFiddle

For Artist
select convert(bit,(count(1)-1))
from table_name
group by artist -- <-- Replace artist with column name for which duplicate

write a select count statement using distinct with specified column and another select count without distinct and compare both of them based on your requirement

you can use 4 different query with union & each query must contain count(column name) + group by clause

Related

sqlite3 recursive aggregation of data

This may be a kind of the Knapsack problem.
I need to traverse a data table, group it by a column, choosing ones with better time.
Then repeat the previous step until a limit given by column CAPACITY is not reached.
This is the demo scenario:
create table if not exists data( vid num, size num, epid num, sid num, capacity num, dt );
delete from data;
insert into data(vid,size,epid,sid,capacity,dt)
values
(0,20,1,1,50,1100), -- 2nd choice
(0,20,1,1,50,1000), -- 1st choice
(0,20,1,1,50,1200), -- last choice excluded because out of capacity
(1,20,2,2,50,1100), -- 2nd choice
(1,20,2,2,50,1000), -- 1st choice
(1,20,2,2,50,1200); -- last choice excluded because out of capacity
This is the non recursive solution:
with best0 as (
select a.rowid as tid,a.vid,a.sid,a.size,a.dt,a.capacity-a.size as remains,0 as level
from data a
group by a.sid
having min(a.dt)
),
best1 as (
select a.tid,a.vid,a.sid,a.size,a.dt,a.remains, a.level
from (
select
a.rowid as tid,a.sid,a.vid,a.size,a.capacity,a.dt,b.remains-a.size as remains,
b.level+1 as level
from data a
join best0 b on b.sid=a.sid -- and b.level=a.level-1
where not a.rowid in (select tid from best0)
and b.remains-a.size>0
) a group by a.sid having min(a.dt)
),
best2 as (
select a.tid,a.vid,a.sid,a.size,a.dt,a.remains, a.level
from (
select
a.rowid as tid,a.sid,a.vid,a.size,a.capacity,a.dt,b.remains-a.size as remains,
b.level+1 as level
from data a
join best1 b on b.sid=a.sid -- and b.level=a.level-1
where not a.rowid in (select tid from best0 union all select tid from best1)
and b.remains-a.size>0
) a group by a.sid having min(a.dt)
)
select * from best0
union all
select * from best1
union all
select * from best2
And this the result:
tid | vid | sid | size | Dtime | capacity | group_level
--- | --- | --- | ---- | ----- | -------- | -----------
2 | 0 | 1 | 20 | 1000 | 30 | 0
5 | 1 | 2 | 20 | 1000 | 30 | 0
1 | 0 | 1 | 20 | 1100 | 10 | 1
4 | 1 | 2 | 20 | 1100 | 10 | 1
This is the recursive version that give error: "recursive reference in a subquery: best"
with recursive best(tid,vid,sid,size,dt,remains,level)
as (
select a.rowid as tid,a.vid,a.sid,a.size,a.dt,a.capacity-a.size as remains,0 as level
from data a
group by a.sid
having min(a.dt)
union all
select a.tid,a.vid,a.sid,a.size,a.dt,a.remains, a.level
from (
select
a.rowid as tid,a.sid,a.vid,a.size,a.dt,b.remains-a.size as remains,
b.level+1 as level
from data a
join best b on b.sid=a.sid -- and b.level=a.level-1
where not a.rowid in (select tid from best) and b.remains-a.size>0
) a group by a.sid having min(a.dt)
)
select * from best
I tried differents solutions even using a loop counter but everyone give the same error.

Is there a way to reuse subqueries in the same query?

See Update at end of question for solution thanks to marked answer!
I'd like to treat a subquery as if it were an actual table that can be reused in the same query. Here's the setup SQL:
create table mydb.mytable
(
id integer not null,
fieldvalue varchar(100),
ts timestamp(6) not null
)
unique primary index (id, ts)
insert into mydb.mytable(0,'hello',current_timestamp - interval '1' minute);
insert into mydb.mytable(0,'hello',current_timestamp - interval '2' minute);
insert into mydb.mytable(0,'hello there',current_timestamp - interval '3' minute);
insert into mydb.mytable(0,'hello there, sir',current_timestamp - interval '4' minute);
insert into mydb.mytable(0,'hello there, sir',current_timestamp - interval '5' minute);
insert into mydb.mytable(0,'hello there, sir. how are you?',current_timestamp - interval '6' minute);
insert into mydb.mytable(1,'what up',current_timestamp - interval '1' minute);
insert into mydb.mytable(1,'what up',current_timestamp - interval '2' minute);
insert into mydb.mytable(1,'what up, mr man?',current_timestamp - interval '3' minute);
insert into mydb.mytable(1,'what up, duder?',current_timestamp - interval '4' minute);
insert into mydb.mytable(1,'what up, duder?',current_timestamp - interval '5' minute);
insert into mydb.mytable(1,'what up, duder?',current_timestamp - interval '6' minute);
What I want to do is return only rows where FieldValue differs from the previous row. This SQL does just that:
locking row for access
select id, fieldvalue, ts from
(
--locking row for access
select
id, fieldvalue,
min(fieldvalue) over
(
partition by id
order by ts, fieldvalue rows
between 1 preceding and 1 preceding
) fieldvalue2,
ts
from mydb.mytable
) x
where
hashrow(fieldvalue) <> hashrow(fieldvalue2)
order by id, ts desc
It returns:
+----+---------------------------------+----------------------------+
| id | fieldvalue | ts |
+----+---------------------------------+----------------------------+
| 0 | hello | 2015-05-06 10:13:34.160000 |
| 0 | hello there | 2015-05-06 10:12:34.350000 |
| 0 | hello there, sir | 2015-05-06 10:10:34.750000 |
| 0 | hello there, sir. how are you? | 2015-05-06 10:09:34.970000 |
| 1 | what up | 2015-05-06 10:13:35.470000 |
| 1 | what up, mr man? | 2015-05-06 10:12:35.690000 |
| 1 | what up, duder? | 2015-05-06 10:09:36.240000 |
+----+---------------------------------+----------------------------+
The next step is to return only the last row per ID. If I were to use this SQL to write the previous SELECT to a table...
create table mydb.reusetest as (above sql) with data;
...I could then do this do get the last row per ID:
locking row for access
select t1.* from mydb.reusetest t1,
(
select id, max(ts) ts from mydb.reusetest
group by id
) t2
where
t2.id = t1.id and
t2.ts = t1.ts
order by t1.id
It would return this:
+----+------------+----------------------------+
| id | fieldvalue | ts |
+----+------------+----------------------------+
| 0 | hello | 2015-05-06 10:13:34.160000 |
| 1 | what up | 2015-05-06 10:13:35.470000 |
+----+------------+----------------------------+
If I could reuse the subquery in my initial SELECT, I could achieve the same results. I could copy/paste the entire query SQL into another subquery to create a derived table, but this would just mean I'd need to change the SQL in two places if I ever needed to modify it.
Update
Thanks to Kristján, I was able to implement the WITH clause into my SQL like this for perfect results:
locking row for access
with items (id, fieldvalue, ts) as
(
select id, fieldvalue, ts from
(
select
id, fieldvalue,
min(fieldvalue) over
(
partition by id
order by ts, fieldvalue
rows between 1 preceding and 1 preceding
) fieldvalue2,
ts
from mydb.mytable
) x
where
hashrow(fieldvalue) <> hashrow(fieldvalue2)
)
select t1.* from items t1,
(
select id, max(ts) ts from items
group by id
) t2
where
t2.id = t1.id and
t2.ts = t1.ts
order by t1.id
Does WITH help? That lets you define a result set you can use multiple times in the SELECT.
From their example:
WITH orderable_items (product_id, quantity) AS
( SELECT stocked.product_id, stocked.quantity
FROM stocked, product
WHERE stocked.product_id = product.product_id
AND product.on_hand > 5
)
SELECT product_id, quantity
FROM orderable_items
WHERE quantity < 10;

SQL SERVER merge two column, combine it, and count the same

I want to create a barcode by merge and combine two column.
here is my table :
ID | Items1 | Items2 | BArcode
001 | Shirt | CPU |
002 | Shirt | CPU |
001 | Shoes | Monitor |
002 | Jacket | Monitor |
001 | Shoes | CPU |
002 | | Keyboard |
002 | | Keyboard |
001 | Shirt | Keyboard |
002 | Shirt | |
The barcode created based on ID+Item1/Items2+Count. The count get from counting how many times one ID have oredered the same item. I want it to display only the data that haven't generated a barcode, so it's when the Barcode column value is null, from the above table the Barcode is null:
ID | Barcode |
001 | 001Shirt1 |
002 | 002Shirt1 |
001 | 001Shoes1 |
002 | 002Jacket1 |
001 | 001Shoes2 |
001 | 001Shirt2 |
002 | 002Shirt2 |
001 | 001CPU1 |
002 | 002CPU1 |
001 | 001Monitor1 |
002 | 002Monitor1 |
001 | 001CPU2 |
002 | 002Keyboard1 |
002 | 002Keyboard2 |
001 | 001Keyboard1 |
here is my first code :
Dim strcommand As String = "select [ID], ([ID] + [Items1])
as Barcode from tbl_Request where [Items1] != 'null'
and Barcode = 'null' union select ([ID] + [Items2])
from tbl_Request where [Items2] != 'Null' and Barcode = 'null'"
it doesn't work. it say "All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists". on my code above I haven't implement the counting yet. does anyone know how to do it?
Thanks in advances....
You can use this query to generate the barcode values:
;with cte as
(select id, item1 item, row_number() over (partition by id, item1 order by getdate()) rn
from items
where item1 is not null and barcode is null
union
select id, item2 item, row_number() over (partition by id, item2 order by getdate()) rn
from items
where item2 is not null and barcode is null)
select id, cast(id as varchar) + item + cast(rn as varchar) barcode
from cte
If you wanted to add this to a new table, say tbl_barcode with columns id and barcode, you would do this:
;with cte as
(select id, item1 item, row_number() over (partition by id, item1 order by getdate()) rn
from items
where item1 is not null and barcode is null
union
select id, item2 item, row_number() over (partition by id, item2 order by getdate()) rn
from items
where item2 is not null and barcode is null)
insert into tbl_barcode (id, barcode)
select id, cast(id as varchar) + item + cast(rn as varchar) barcode
from cte
The error that you are getting is that the union join that you have created does not contain the same fields in the second select statement, as your original select statement. SQL UNION Operator, Notice that each SELECT statement within the UNION must have the same number of columns.
So therefore you will need to change
select ([ID] + [Items2])
to
select [ID], ([ID] + [Items2])
declare #x table (ID varchar(20),Items1 VARCHAR(10),Items2 VARCHAR(10),BARCODE INT)
INSERT INTO #x
(ID,Items1,Items2,BARCODE)
VALUES ('001','Shirt','CPU',NULL)
INSERT INTO #x
(ID,Items1,Items2,BARCODE)
VALUES ('001',NULL,'Monitor',NULL)
INSERT INTO #x
(ID,Items1,Items2,BARCODE)
VALUES ('002','TRouser','Monitor',NULL)
select ID,
Case when Items1 IS NOT NULL Then ID +Items1+
CAST(DENSE_RANK()OVER(PARTITION by Items1 order by Items1 desc)AS VARCHAR)
when Items2 IS NOT NULL Then ID +Items2+
CAST(DENSE_RANK()OVER(PARTITION by Items2 order by Items1 desc)AS VARCHAR)
ELSE '' END AS Barcode from #x

SQLite help for joining and count

I have 2 tables:
tblTransactions:
transID | type | userID
tblusers:
userID | name ;
Now I want my results to be like:
name |count( transactionType1(where type=1)) | transactionType1(where type=2)
mr.1 | 2 | 4
mr.2 | 3 | 5
Thanks for your help
Group by the user and then you can use aggregate functions like sum to count the type (with a condition)
select u.name,
sum(type = 1) as type1_count,
sum(type = 2) as type2_count
from tblusers u
left join tblTransactions t on u.userid = t.userid
group by u.name

SQLite Select data from multiple rows returned as one row

I would like to know whether it is possible to use a SELECT statement in SQLite to merge the data from two rows into one, similar to how is suggested in the SQL Server forum below.
Consider the scenario below which is based on SQL Server (taken from http://forums.aspfree.com/microsoft-sql-server-14/merge-the-two-rows-in-one-row-245550.html)
Given there is a table
Emp
ID | Name |
1 | x |
1 | P |
2 | y |
2 | Q |
3 | W |
We want the resulting data from the select statement to output:
Emp_Data
Id | Name-1 | Name-2 |
1 | x | P |
2 | y | Q |
3 | w | |
The answer in the post suggests the following SQL as a possible solution:
SELECT
a.ID,
[Name-1] = ISNULL((
SELECT TOP 1 Name
FROM emp
WHERE ID = a.ID),''),
[Name-2] = ISNULL((
SELECT TOP 1 b.Name
FROM emp b
WHERE b.ID = a.ID
AND Name NOT IN(
SELECT TOP 1 Name
FROM emp
WHERE ID = b.ID
)),'')
FROM emp a
GROUP BY a.ID
Using SQLite is it possible to generate the columns [Name-1] & [Name-2] using nested SELECT statements like we can do above in SQL Server?
SELECT
a.ID,
COALESCE(a.Name,'') as "Name-1",
COALESCE((SELECT b.Name FROM Emp b
WHERE b.ID = a.ID
AND b.rowid != a.rowid LIMIT 1),'') as "Name-2"
FROM emp a
GROUP BY a.ID
Doug's solution didn't work for me. The code below, however, did work for me but it's very slow...
SELECT
a.ID,
a.Name AS Name1,
(SELECT b.Name FROM Emp b
WHERE b.ID = a.ID
AND b.Name != a.Name LIMIT 1) AS Name2
FROM emp a
GROUP BY a.ID
try this:::
select id, group_concat(name) from emp group by id;
;)

Resources