Let's say i have a table, Product. This contains several Products with different vatpercentages and vatprices:
Product
ArticleId | Price | VatPercentage | VatPrice
(integer) (numeric) (varchar) (numeric)
--------------------------------------------
1 100 25.0000000000 25
2 80 25.0000000000 20
3 50 8.0000000000 4
4 70 8.0000000000 5.6
5 20 0 0
0
Now i need to build strings using Group_concat and sum prices by vatpercentage where VatPrice is not 0 and price is not 0.
The result i want back in this case:
{a}25{b}45 SEK{c}{a}8{b}9.6 SEK{c}
The code i've tried:
select
group_concat('{a}' ||
CAST(VatPercentage as integer) ||
'{b}' || SUM(VatPrice) ||
' SEK' || '{c}','')
FROM Product
group by VatPercentage
having Count(Price) > 0
Fiddle
Thanks on forehand
Do the regular concatenation in a subquery, then use GROUP_CONCAT in an outer query, because you can't use one aggregation function in the arguments to another.
SELECT GROUP_CONCAT(Result, '|') Results
FROM (
SELECT 'VatPercentage:' || CAST(VatPercentage AS INTEGER) || '% VatPrice: '
|| SUM(VatPrice) Result
FROM Product
WHERE VatPercentage != '0'
GROUP BY VatPercentage) x
You also don't need the HAVING clause. That just excludes results where all the Price values are NULL. But your sample result is skipping rows where VatPercentage is zero, so I've put that in the WHERE clause.
DEMO
Related
Ok, It will be much clearer once if done a Example:
RowId Name ID1 ID2 ID3 ID4 ID5 ID6 ID7 ID8 ID9 ID10
1 Alex 11 22 0 0 0 0 14 44 0 0
2 John 0 23 0 0 44 0 33 88 0 77
Ok, i want to get following result:
Alex 11 22 14 44
So the first part of the Query is clear,
Select *
from Table
where Name = Alex AND *Now im not sure if i need to use IS NOT NULL or => 1*
The following will produce the required result :-
SELECT
Name ||' '||
CASE WHEN coalesce(id1,0) <> 0 THEN id1||' ' ELSE '' END
||CASE WHEN coalesce(id2,0) <> 0 THEN id2||' ' ELSE '' END
||CASE WHEN coalesce(id3,0) <> 0 THEN id3||' ' ELSE '' END
||CASE WHEN coalesce(id4,0) <> 0 THEN id4||' ' ELSE '' END
||CASE WHEN coalesce(id5,0) <> 0 THEN id5||' ' ELSE '' END
||CASE WHEN coalesce(id6,0) <> 0 THEN id6||' ' ELSE '' END
||CASE WHEN coalesce(id7,0) <> 0 THEN id7||' ' ELSE '' END
||CASE WHEN coalesce(id8,0) <> 0 THEN id8||' ' ELSE '' END
||CASE WHEN coalesce(id9,0) <> 0 THEN id9||' ' ELSE '' END
||CASE WHEN coalesce(id10,0) <> 0 THEN id10||' ' ELSE '' END
AS myidlist
FROM mytable
WHERE Name = 'Alex'
;
the coalesce function, as used,turns null into 0 simplyfying the condition check. An alternative would be to use CASE WHEN id1 <> 0 AND id1 IS NOT NULL THEN id1||' ' ELSE '' END
However, the result will possibly be of little use or complicated to manipulate as a result (e.g. where do the numeric values come from such as what does 22 mean other than it's one of the values stored in one of the ID? columns).
Alternative approach
This approach assumes that you have a variable number of values per name (this may not necessarily be what you want).
Consider the following that, rather than using numerous columns to store the values RELATED to a name (related highlighted as SQLite is a relational database), it stores those values in a related table using a one-to-many relationship (there are many values each is realted to 1 name).
This bit creates the alternative structure/schema i.e. 2 tables one for the parent data another for the child data (the parent can have 0- many children each being a value)
CREATE TABLE IF NOT EXISTS mytable2 (Name TEXT PRIMARY KEY);
CREATE TABLE IF NOT EXISTS mytable2_ids (
Name_reference TEXT
REFERENCES mytable2(Name) ON DELETE CASCADE ON UPDATE CASCADE -- optional Foreign Key
,
id INTEGER
);
This inserts the data equivalent to you original data.
INSERT INTO mytable2 VALUES('Alex'),('John');
INSERT INTO mytable2_ids VALUES
('Alex',11),('Alex',22),('Alex',14),('Alex',44)
, ('John',23),('John',44),('John',33),('John',88),('John',77)
;
This is the query that produces the same result :-
SELECT Name||group_concat(id,' ') AS myidlist FROM mytable2 JOIN mytable2_ids ON Name = Name_reference WHERE name = 'Alex';
group_concat is an aggregate function that concatenates all the values of a group of data. In this case the group is all of the data as there is no GROUP BY clause. So it takes ALL of the values in the id columnof the JOINED (related) mytable2_ids and concatenates them.
The result being :-
I want to display the hourly based report for the last 24 hour. I have tried but the problem is that it will display count only where particular hour contains data.
But I want to display count for an hour and if count not found then display 0 over there.
select
datepart(hour, upload_date) as [hour], count(*)
from
tbl_stories
where
upload_date > getdate() - 1
group by
datepart(hour, upload_date)
Output:
hour count
-------------
11 2
16 1
17 1
but I want to get a record in the following way.
hour count
-------------
1 0
2 0
3 5
.
.
.
.
24 1
You can use a value() clause to generate all the hours and then use left join:
select v.hh, count(s.upload_date)
from (values (0), (1), . . . (23)
) v(hh) left join
tbl_stories s
on datepart(hour, s.upload_date) = v.hh and
s.upload_date > getdate() - 1
group by v.hh
order by v.hh;
Note that hours go from 0 to 23.
If you don't want to list out the hours, a convenient generation method is a recursive CTE:
with hours as (
select 1 as hh
union all
select hh + 1
from hours
where hh < 23
)
select h.hh, count(s.upload_date)
from hours h
tbl_stories s
on datepart(hour, s.upload_date) = h.hh and
s.upload_date > getdate() - 1
group by h.hh
order by h.hh;
I need to select all rows (for a range) which have a common value within a column.
For example (starting from the last row)
I try to select all of the rows where _user_id == 1 until _user_id != 1 ?
In this case resulting in selecting rows [4, 5, 6]
+------------------------+
| _id _user_id amount |
+------------------------+
| 1 1 777 |
| 2 2 1 |
| 3 2 11 |
| 4 1 10 |
| 5 1 100 |
| 6 1 101 |
+------------------------+
/*Create the table*/
CREATE TABLE IF NOT EXISTS t1 (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
_user_id INTEGER,
amount INTEGER);
/*Add the datas*/
INSERT INTO t1 VALUES(1, 1, 777);
INSERT INTO t1 VALUES(2, 2, 1);
INSERT INTO t1 VALUES(3, 2, 11);
INSERT INTO t1 VALUES(4, 1, 10);
INSERT INTO t1 VALUES(5, 1, 100);
INSERT INTO t1 VALUES(6, 1, 101);
/*Check the datas*/
SELECT * FROM t1;
1|1|777
2|2|1
3|2|11
4|1|10
5|1|100
6|1|101
In my attempt I use Common Table Expressions to group the results of _user_id. This gives the index of the last row containing a unique value (eg. SELECT _id FROM t1 GROUP BY _user_id LIMIT 2; will produce: [6, 3])
I then use those two values to select a range where LIMIT 1 OFFSET 1 is the lower end (3) and LIMIT 1 is the upper end (6)
WITH test AS (
SELECT _id FROM t1 GROUP BY _user_id LIMIT 2
) SELECT * FROM t1 WHERE _id BETWEEN 1+ (
SELECT * FROM test LIMIT 1 OFFSET 1
) and (
SELECT * FROM test LIMIT 1
);
Output:
4|1|10
5|1|100
6|1|101
This appears to work ok at selecting the last "island" but what I really need is a way to select the n'th island.
Is there a way to generate a query capable of producing outputs like these when provided a parameter n?:
island (n=1):
4|1|10
5|1|100
6|1|101
island (n=2):
2|2|1
3|2|11
island (n=3):
1|1|777
Thanks!
SQL tables are unordered, so the only way to search for islands is to search for consecutive _id values:
WITH RECURSIVE t1_with_islands(_id, _user_id, amount, island_number) AS (
SELECT _id,
_user_id,
amount,
1
FROM t1
WHERE _id = (SELECT max(_id)
FROM t1)
UNION ALL
SELECT t1._id,
t1._user_id,
t1.amount,
CASE WHEN t1._user_id = t1_with_islands._user_id
THEN island_number
ELSE island_number + 1
END
FROM t1
JOIN t1_with_islands ON t1._id = (SELECT max(_id)
FROM t1
WHERE _id < t1_with_islands._id)
)
SELECT *
FROM t1_with_islands
ORDER BY _id;
I have two tables, CustomerCategories and Articles. Both tables have a column called VatPercentage and VatPrice.
Scenarios:
In case of same vatpercentage exists in both tables i want to sum the vatprice from both tables and add it to the string.
In case of vatpercentage only exists in CustomerCategories table i want to sum the vatprice from here and add it to the string.
In case of vatpercentage only exists in Articles table i want to sum the vatprice from here and add it to the string.
Example tables:
Articles:
ArticleId TotalPrice VatPercentage VatPrice
1 100 25.0000000000 25
2 80 25.0000000000 20
3 50 8.0000000000 4
4 70 8.0000000000 5.6
5 20 0 0
6 0 0 0
CustomerCategories:
CustomerCategoryId TotalPrice VatPercentage VatPrice
2 163 8.0000000000 13
2 163 13.0000000000 13
2 163 0 0
2 150 25.0000000000 37.5
The result i want back from the Query in this case:
{esc}{40h}25 %{esc}{41h}82.5 NOK{lf}{esc}{40h}8 %{esc}{41h}22.6 NOK{lf}{esc}{40h}13 %{esc}{41h}13 NOK{lf}
The code i've trying without any positive results is:
SELECT GROUP_CONCAT(Result, '|') Results
FROM (
select case when cc.VatPercentage = a.VatPercentage
then
SELECT '{esc}{40}' || CAST(cc.VatPercentage AS INTEGER) || '% ' ||
(SUM(cc.VatPrice) + SUM(a.VatPrice)) || ' NOK' || '{lf}' Result end
else
(
case when cc.VatPercentage <> a.VatPercentage
then
SELECT '{esc}{40}' || CAST(cc.VatPercentage AS INTEGER) || '% ' ||
(SUM(cc.VatPrice) + SUM(a.VatPrice)) || ' NOK' || '{lf}' ||
SELECT '{esc}{40}' || CAST(a.VatPercentage AS INTEGER) || '% ' ||
(SUM(a.VatPrice)) || ' NOK' || '{lf}' Result
end
)
FROM CustomerCategories cc
LEFT JOIN Articles a
on cc.VatPercentage = a.VatPercentage
WHERE
cc.VatPercentage != '0'
AND a.VatPercentage != '0'
AND cc.TotalPrice != '0'
AND a.TotalPrice != '0'
GROUP BY
cc.VatPercentage OR a.VatPercentage) x
Help would be appreciated.
Fiddle
First, combine both tables:
SELECT VatPercentage, VatPrice FROM CustomerCategories
UNION ALL
SELECT VatPercentage, VatPrice FROM Articles
VatPercentage VatPrice
8.0000000000 13
13.0000000000 13
0 0
25.0000000000 37.5
25.0000000000 25
25.0000000000 20
8.0000000000 4
8.0000000000 5.6
0 0
0 0
Then do a simple GROUP BY over that:
SELECT VatPercentage,
SUM(VatPrice) AS PriceSum
FROM (SELECT VatPercentage, VatPrice FROM CustomerCategories
UNION ALL
SELECT VatPercentage, VatPrice FROM Articles)
WHERE VatPercentage != '0'
GROUP BY VatPercentage
Then do the escape characters mess over the result of that:
SELECT GROUP_CONCAT('{esc}{40h}' || VatPercentage || ' %' ||
'{esc}{41h}' || VatPrice || ' NOK{lf}',
'')
FROM (SELECT VatPercentage,
SUM(VatPrice) AS PriceSum
FROM (SELECT VatPercentage, VatPrice FROM CustomerCategories
UNION ALL
SELECT VatPercentage, VatPrice FROM Articles)
WHERE VatPercentage != '0'
GROUP BY VatPercentage)
I have a sample table with following values
SNO | Mon
-----+-------
100 | 1
101 | 1
102 | 1
100 | 2
101 | 2
102 | 2
100 | 3
101 | 3
Now I need a query to count the total sno's which are in 3 months
The result should be 2, as 100 & 101 are in mon 1,2 and 3. However, 102 is only present in mon 1,2.
Thanks,
RK
This Query in theory should work.
SELECT
tmpTbl.sNo
FROM
tmpTbl
GROUP BY
tmpTbl.sNo
HAVING
Count(tmpTbl.monNo) = (SELECT Count(*) FROM (SELECT tmpTbl.monNo FROM tmpTbl GROUP BY tmpTbl.monNo));
The result would be,
sNo
----
100
101
I have used two SubQueries to get the result. Teh both are used in the HAVING clause of the SQL. First SqubQuery (inner most). Will get the number of Unique Month's available in your table, the outer SubQuery will then Count the number of Unique months. So the Overall Query can be translated as "SELECT the serial number FROM the table HAVING the Count of Month equal to the Number of unique records in the same table".
The reason I used SbQuery instead of a number is because of the fact this will also be applicable when your month number increases. Hope this helps !
EDIT
Here is the Query for getting the count.
SELECT
Count(*) As simpleCount
FROM
(
SELECT
tmpTbl.sNo
FROM
tmpTbl
GROUP BY
tmpTbl.sNo
HAVING
Count(tmpTbl.monNo) = (SELECT Count(*) FROM (SELECT tmpTbl.monNo FROM tmpTbl GROUP BY tmpTbl.monNo))
);