Count in the SUM SQL - sql

I have the sql function like the following:
SELECT
SUM(3 * tb_spp.bulanan_spp ),
COUNT(tb_bulan.id) AS JUMLAH,
SUM( count(tb_bulan.id) * tb_angsuran_spp.nominal_spp ),
SUM( (3 * tb_spp.bulanan_spp) - (3 * tb_angsuran_spp.nominal_spp) ) as SPP
FROM tb_spp, tb_angsuran_spp, tb_bulan
where tb_spp.id_siswa = tb_angsuran_spp.id_siswa and tb_spp.id_siswa = '1'
and tb_bulan.id = tb_angsuran_spp.id_bulan
and tb_bulan.id between '1' and '2'
But when i run the error message appears '# 1111 - Invalid use of group function'
What is the cause and how is the solution?

sum(count()) isn't generally allowed. There are a few other changes I would make to the query as well:
SELECT SUM( 3 * s.bulanan_spp ),
count(b.id) as JUMLAH,
SUM(a.nominal_spp ),
SUM( (3 * s.bulanan_spp) - (3 * a.nominal_spp) ) as SPP
FROM tb_spp s JOIN
tb_angsuran_spp a
on s.id_siswa = a.id_siswa join
tb_bulan b
on b.id = a.id_bulan
where s.id_siswa = 1 and
b.id between 1 and 2;
Notes:
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
Table aliases make the query easier to write and to read.
Ids are usually numbers; hence I removed the single quotes (they are appropriate for strings).
I'm not sure that your sums and counts will produce correct answers. If not, ask another question, including sample data and desired results. This answer addresses the syntax problems in this question.

Related

How to cast only the part of a table using a single SQL command in PostgreSQL

In a PostgreSQL table I have several information stored as text. It depends on the context described by a type column what type of information is stored. The application is prepared to get by only one command the Id's of the row.
I got into trouble when i tried to compare the information (bigint stored as a string) with an external value (e.g. '9' > '11'). When I tried to cast the column, the datatbase return an error (not all values in the column are castable, e.g. datetime or normal text). Also when I try to cast only the result of a query command, I get a cast error.
I get the table with the castable rows by this command:
SELECT information.id as id, item.information::bigint as item
FROM information
INNER JOIN item
ON information.id = item.informationid
WHERE information.type = 'task'
The resulting rows are showing up only text that is castable. When I throw it into another command it results in an error.
SELECT x.id FROM (
SELECT information.id as id, item.information::bigint as item
FROM information
INNER JOIN item
ON information.id = item.informationid
WHERE information.type = 'task'
) AS x
WHERE x.item > '0'::bigint
Accroding to the error, the database tried to cast all rows in the table.
Technically, this happens because the optimizer thinks WHERE x.item > '0'::bigint is a much more efficient filter than information.type = 'task'. So in the table scan, the WHERE x.item > '0'::bigint condition is chosen to be the predicate. This thinking is not wrong but will make you fall into this seemingly illogical trouble.
The suggestion by Gordon to use CASE WHEN inf.type = 'task' THEN i.information::bigint END can avoid this, but however it may sometimes ruin your idea to put that as a sub-query and require the same condition to be written twice.
A funny trick I tried is to use OUTER APPLY:
SELECT x.* FROM (SELECT 1 AS dummy) dummy
OUTER APPLY (
SELECT information.id as id, item.information::bigint AS item
FROM information
INNER JOIN item
ON information.id = item.informationid
WHERE information.type = 'task'
) x
WHERE x.item > '0'::bigint
Sorry that I only verified the SQL Server version of this. I understand PostgreSQL has no OUTER APPLY, but the equivalent should be:
SELECT x.* FROM (SELECT 1 AS dummy) dummy
LEFT JOIN LATERAL (
SELECT information.id as id, item.information::bigint AS item
FROM information
INNER JOIN item
ON information.id = item.informationid
WHERE information.type = 'task'
) x ON true
WHERE x.item > '0'::bigint
(reference is this question)
Finally, a more tidy but less flexible method is add the optimizer hint to turn off it to force the optimizer to run the query as how it is written.
This is unfortunate. Try using a case expression:
SELECT inf.id as id,
(CASE WHEN inf.type = 'task' THEN i.information::bigint END) as item
FROM information inf JOIN
item i
ON inf.id = i.informationid
WHERE inf.type = 'task';
There is no guarantee that the WHERE filter is applied before the SELECT. However, CASE does guarantee the order of evaluation, so it is safe.

conditional IIF in a JOIN

I have the next data base:
Table Bill:
Table Bill_Details:
And Table Type:
I want a query to show this result:
The query as far goes like this:
SELECT
Bill.Id_Bill,
Type.Id_Type,
Type.Info,
Bill_Details.Deb,
Bill_Details.Cre,
Bill.NIT,
Bill.Date2,
Bill.Comt
FROM Type
RIGHT JOIN (Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill)
ON Type.Id_Type = Bill_Details.Id_Type
ORDER BY Bill.Id_Bill, Type.Id_Type;
With this result:
I'm not sure how to deal or how to include this:
Type.600,
Type."TOTAL",
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) >= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), "" ),
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) <= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), "" )
The previous code is the responsable of include new data in some fields, since all of the other fields will carry the same data of the upper register. I'll apreciate some sugestions to acomplish this.
Here is a revised version of the UNION which you removed from the question. The original query was a good start, but you just did not provide sufficient details about the error or problem you were experiencing. My comments were not meant to have you remove the problem query, only that you needed to provide more details about the error or problem. In the future if you have a UNION, make sure the each query of the UNION works separately. Then you could debug problems easier, one step at a time.
Problems which I corrected in the second query of the UNION:
Removed reference to table [Type] in the query, since it was not part of the FROM clause. Instead, I replaced it with a literal value.
Fixed FROM clause to join both [Bill] and [Bill_Details] tables. You had fields from both tables, so why would you not join on them just like in the first query of the UNION?
Grouped on all fields from table [Bill] referenced in the SELECT clause. You must either group on all fields, or include them in aggregate expressions like Sum() or First(), etc.
Replaced empty strings with Nulls for the False cases on Iif() statements.
SELECT
Bill.Id_Bill, Type.Id_Type, Type.Info,
Bill_Details.Deb,
Bill_Details.Cre,
Bill.NIT, Bill.Date2, Bill.Comt
FROM
Type RIGHT JOIN (Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill)
ON Type.Id_Type = Bill_Details.Id_Type;
UNION
SELECT
Bill.Id_Bill, 600 As Id_Type, "TOTAL" As Info,
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) >= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), Null ) As Deb,
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) <= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), Null ) As Cre,
Bill.NIT, Bill.Date2, Bill.Comt
FROM Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill
GROUP BY Bill.Id_Bill, Bill.NIT, Bill.Date2, Bill.Comt;

Get URL from the column

I want to get the URL from the Taskdescription tab and fetch it in other column with the name URL. Right now I am using this code
select
c.StreamName AS Category,
ProcessInstanceAppianID as jobId,
a.ProcessInstanceName,
a.ProcessInstanceTargetDate AS TargetDate,
a.ProcessInstanceDescription as TaskDescription,
b.Name as department,
SUBSTRING(ProcessInstanceName, NULLIF(PATINDEX('%[0-9][0-9][0-9][0-9][0-9]%',ProcessInstanceName),0),7) as code
from InternalUseOnly..ProcessInstance a
join InternalUseOnly..Departments b on
b.KeyDepartment = a.KeyDepartmentEntered
AND b.updoperation < 2
join InternalUseOnly..ProcessStream c on
c.KeyProcessStream = a.KeyProcessStream
and c.updoperation < 2
where ProcessInstanceCompleted is null
and a.KeyProcessStream in (330)
and a.updoperation <2
Thanks in advance
If you are using SQL Server, then this will do the trick
SELECT substring(ProcessInstanceDescription , charindex('http://', ProcessInstanceDescription ), charindex('KeyInstr', ProcessInstanceDescription ) - charindex('http://', ProcessInstanceDescription ))
FROM InternalUseOnly..ProcessInstance;
Here is a SQLFiddle
Let's just say I'm in a good mood today, here's the code you need. The URL will be in the first column.
select
substring(a.ProcessInstanceDescription , charindex('http://', a.ProcessInstanceDescription ), charindex('KeyInstr', a.ProcessInstanceDescription ) - charindex('http://', a.ProcessInstanceDescription )),
c.StreamName AS Category,
ProcessInstanceAppianID as jobId,
a.ProcessInstanceName,
a.ProcessInstanceTargetDate AS TargetDate,
a.ProcessInstanceDescription as TaskDescription,
b.Name as department,
SUBSTRING(ProcessInstanceName, NULLIF(PATINDEX('%[0-9][0-9][0-9][0-9][0-9]%',ProcessInstanceName),0),7) as code
from InternalUseOnly..ProcessInstance a
join InternalUseOnly..Departments b on
b.KeyDepartment = a.KeyDepartmentEntered
AND b.updoperation < 2
join InternalUseOnly..ProcessStream c on
c.KeyProcessStream = a.KeyProcessStream
and c.updoperation < 2
where ProcessInstanceCompleted is null
and a.KeyProcessStream in (330)
and a.updoperation <2
update:
Regarding the Invalid length parameter passed to the LEFT or SUBSTRING function. error, this means that you have somewhere in ProcessInstanceDescription column, a row that doesn't fit the format for my SUBSTRING().
Good luck finding it as this is another question and I am not going to give you the solution to it, first of all because information is insufficient and your are not cooperative and apparently unwilling to do some effort yourself.

T-SQL Sum Values of Like Rows

I currently use this select statement in SSRS to report Recent Demand and Days of Inventory to end users.
select Issue.MATERIAL_NUMBER,
SUM(Issue.SHIPPED_QTY)AS DEMAND_QTY,
Main.QUANTITY_TOTAL_STOCK / SUM(Issue.SHIPPED_QTY) * 122 AS [DOI]
From AGS_DATAMART.dbo.GOODS_ISSUE AS Issue
join AGS_DATAMART.dbo.OPR_MATERIAL_DIM AS MAT on MAT.MATERIAL_NUMBER = Issue.MATERIAL_NUMBER
join AGS_DATAMART.dbo.SCE_ECC_MAIN_FINAL_INV_FACT AS MAIN on MAT.MATERIAL_SID = MAIN.MATERIAL_SID
join AGS_DATAMART.dbo.SCE_PLANT_DIM AS PLANT on PLANT.PLANT_SID = MAIN.PLANT_SID
Where Issue.SHIP_TO_CUSTOMER_ID = #CUSTID
and Issue.ACTUAL_PGI_DATE > GETDATE() - 122
and PLANT.PLANT_CODE = #CUSTPLANT
and MAIN.STORAGE_LOCATION = '0001'
Group by Issue.MATERIAL_NUMBER,Main.QUANTITY_TOTAL_STOCK
Pretty Simple.
But is has come to my attention, that they have similar Material Numbers whos values need to be combined.
Material | Qty
0242-55161W 1
0242-55161 3
The two Material Numbers above should be combined and reported as 0242-55161 Qty 4.
How do I combine rows like this? This is just 1 of many queries that will need to be adjusted. Is it possible?
EDIT - The similar material will always be the base number plus the "W", if that matters.
Please note I am brand new to SQL and SSRS, and this is my first time posting here.
Let me know if I need to include any other details.
Thanks in advance.
Answer;
Using just replace, it kept returning 2 unique lines even when using SUM.
I was able to get the desired result using the following. Can you see anything wrong with this method?
with Issue_Con AS
(
select replace(Issue.MATERIAL_NUMBER,'W','') As [MATERIAL_NUMBER],
Issue.SHIPPED_QTY AS [SHIPPED_QTY]
From AGS_DATAMART.dbo.GOODS_ISSUE AS Issue
Where Issue.SHIP_TO_CUSTOMER_ID = #CUSTSHIP
and Issue.SALES_ORDER_TYPE_CODE = 'ZTPC'
and Issue.ACTUAL_PGI_DATE > GETDATE() - 122
)
select Issue_Con.MATERIAL_NUMBER,
SUM(Issue_Con.SHIPPED_QTY)AS [DEMAND_QTY],
Main_Con.QUANTITY_TOTAL_STOCK / SUM(Issue_Con.SHIPPED_QTY) * 122 AS [DOI]
From Issue_Con
join Main_Con on Main_Con.MATERIAL_Number = Issue_Con.MATERIAL_Number
Group By Issue_Con.MATERIAL_NUMBER, Main_Con.QUANTITY_TOTAL_STOCK;
You need to replace Issue.MATERIAL_NUMBER in the select and group by with something else. What that something else is depends on your data.
If it's always 10 digits with anything afterwards ignored, then you can use substr(Issue.MATERIAL_NUMBER, 1, 10)
If the extraneous character is always W and there are no Ws in the proper number, then you can use replace(Issue.MATERIAL_NUMBER, 'W', '')
If it's anything from the first alphabetic character, then you can use case when patindex('%[A-Za-z]%', Issue.MATERIAL_NUMBER) = 0 then Issue.MATERIAL_NUMBER else substr(Issue.MATERIAL_NUMBER, 1, patindex('%[A-Za-z]%', Issue.MATERIAL_NUMBER)) end
You could group your data by this expression instead of MATERIAL_NUMBER:
CASE SUBSTRING(MATERIAL_NUMBER, LEN(MATERIAL_NUMBER), 1)
WHEN 'W' THEN LEFT(MATERIAL_NUMBER, LEN(MATERIAL_NUMBER) - 1)
ELSE MATERIAL_NUMBER
END
That is, check if the last character is W. If it is, return all but the last character, otherwise return the entire value.
To avoid repeating the same expression twice (once in GROUP BY and once in SELECT) you could use a subselect, for example like this:
select Issue.MATERIAL_NUMBER_GROUP,
SUM(Issue.SHIPPED_QTY)AS DEMAND_QTY,
Main.QUANTITY_TOTAL_STOCK / SUM(Issue.SHIPPED_QTY) * 122 AS [DOI]
From (
SELECT
*,
CASE SUBSTRING(MATERIAL_NUMBER, LEN(MATERIAL_NUMBER), 1)
WHEN 'W' THEN LEFT(MATERIAL_NUMBER, LEN(MATERIAL_NUMBER) - 1)
ELSE MATERIAL_NUMBER
END AS MATERIAL_NUMBER_GROUP
FROM AGS_DATAMART.dbo.GOODS_ISSUE
) AS Issue
join AGS_DATAMART.dbo.OPR_MATERIAL_DIM AS MAT on MAT.MATERIAL_NUMBER = Issue.MATERIAL_NUMBER
join AGS_DATAMART.dbo.SCE_ECC_MAIN_FINAL_INV_FACT AS MAIN on MAT.MATERIAL_SID = MAIN.MATERIAL_SID
join AGS_DATAMART.dbo.SCE_PLANT_DIM AS PLANT on PLANT.PLANT_SID = MAIN.PLANT_SID
Where Issue.SHIP_TO_CUSTOMER_ID = #CUSTID
and Issue.ACTUAL_PGI_DATE > GETDATE() - 122
and PLANT.PLANT_CODE = #CUSTPLANT
and MAIN.STORAGE_LOCATION = '0001'
Group by Issue.MATERIAL_NUMBER_GROUP,Main.QUANTITY_TOTAL_STOCK

multiple count(distinct)

I get an error unless I remove one of the count(distinct ...). Can someone tell me why and how to fix it?
I'm in vfp. iif([condition],[if true],[else]) is equivalent to case when
SELECT * FROM dpgift where !nocalc AND rectype = "G" AND sol = "EM112" INTO CURSOR cGift
SELECT
list_code,
count(distinct iif(language != 'F' AND renew = '0' AND type = 'IN',donor,0)) as d_Count_E_New_Indiv,
count(distinct iif(language = 'F' AND renew = '0' AND type = 'IN',donor,0)) as d_Count_F_New_Indiv /*it works if i remove this*/
FROM cGift gift
LEFT JOIN
(select didnumb, language, type from dp) d
on cast(gift.donor as i) = cast(d.didnumb as i)
GROUP BY list_code
ORDER by list_code
edit:
apparently, you can't use multiple distinct commands on the same level. Any way around this?
VFP does NOT support two "DISTINCT" clauses in the same query... PERIOD... I've even tested on a simple table of my own, DIRECTLY from within VFP such as
select count( distinct Col1 ) as Cnt1, count( distinct col2 ) as Cnt2 from MyTable
causes a crash. I don't know why you are trying to do DISTINCT as you are just testing a condition... I more accurately appears you just want a COUNT of entries per each category of criteria instead of actually DISTINCT
Because you are not "alias.field" referencing your columns in your query, I don't know which column is the basis of what. However, to help handle your DISTINCT, and it appears you are running from WITHIN a VFP app as you are using the "INTO CURSOR" clause (which would not be associated with any OleDB .net development), I would pre-query and group those criteria, something like...
select list_code,
donor,
max( iif( language != 'F' and renew = '0' and type = 'IN', 1, 0 )) as EQualified,
max( iif( language = 'F' and renew = '0' and type = 'IN', 1, 0 )) as FQualified
from
list_code
group by
list_code,
donor
into
cursor cGroupedByDonor
so the above will ONLY get a count of 1 per donor per list code, no matter how many records that qualify. In addition, if one record as an "F" and another does NOT, then you'll have a value of 1 in EACH of the columns... Then you can do something like...
select
list_code,
sum( EQualified ) as DistEQualified,
sum( FQualified ) as DistFQualified
from
cGroupedByDonor
group by
list_code
into
cursor cDistinctByListCode
then run from that...
You can try using either another derived table or two to do the calculations you need, or using projections (queries in the field list). Without seeing the schema, it's hard to know which one will work for you.