GroupBy Count With Subsonic 3 - c#

I like to perform the following with SubSonic 3 without using Linq (using dynamic lookup of columns and tables). Also, no inline sql (to prevent sql-injections).
http://www.java2s.com/Code/SQL/Select-Clause/COUNTandGROUPBY.htm
mysql> SELECT species, COUNT(*) FROM Bird GROUP BY species;
+---------+----------+
| species | COUNT(*) |
+---------+----------+
| Bus | 2 |
| Car | 1 |
+---------+----------+
2 rows in set (0.00 sec)
Drop table Bird;
CREATE TABLE Bird (
name VARCHAR(20),
owner VARCHAR(20),
species VARCHAR(20),
sex CHAR(1),
birth DATE,
death DATE
);
INSERT INTO Bird VALUES ('BlueBird','Joe','Car','f','1999-03-30',NULL);
INSERT INTO Bird VALUES ('RedBird','Yin','Bus','m','1979-04-30',1998-01-30);
INSERT INTO Bird VALUES ('RedBird','Yin','Bus','m','1998-01-30',NULL);
/* COUNT() and GROUP BY
Number of animals per species:
*/
SELECT species, COUNT(*) FROM Bird GROUP BY species;

You almost did it:
Try This:
SELECT species, COUNT() FROM Bird GROUP BY species;
This Work in SQL and i think it works in MySql

Related

Remove need for second T-SQL query

I am loading some data into a repeater which is coming from two tables. The query against the second table is only selecting the MAX record though, and because of this complexity, I'm having to create a child repeater to then go off and find the Max record to display.
Table A: Activity List
ID | Activity
----+-----------------------
1 | Change Oil Filter
2 | Change brake fluid
3 | Change brake rotors
Table B: Mechanics Log
ID | ActivityID | Date | Mechanic | Comment
---+-------------+-------------+-------------------------------------------
1 | 1 | 2019-27-06 | John | Changed the oil filter
2 | 1 | 2019-26-06 | Sally | No oil filters in stock.
3 | 2 | 2019-20-06 | Sally | Brake fluid flushed.
As stated above, I can produce the following table using two repeaters (one inside the other) and it looks like this.
ActivityID | Date | Mechanic | Comment
-------------+-------------+-----------------------------------------
1 | 2019-27-06 | John | Changed the oil filter
2 | 2019-20-06 | Sally | Brake fluid flushed.
3 | | |
My question is: How can I produce the same table but using only one repeater and 1 T-SQL query? Is it possible? The reason being is that this is a very simple list (shortened for this demonstration) of the full list I have to enable for my mechanics work log, and when i start going to 100+ activities that can be done on a vehicle, the page loads quite slow; assuming because it has to fire off the 2nd repeater + code for each record it has bound.
I also apologize I do not yet have a 'starting point' for you to work with, as nothing I have created has come even close to producing the result in one query. I am having trouble working out how I combine the first part of the query with the MAX(Date) of the 2nd table. Hoping for some assistance from the community to help.
You can use the below query to get the desired result -
Sample Data
Declare #ActivityList Table
(ID int, Activity varchar(100))
Insert into #ActivityList
values
(1 , 'Change Oil Filter' ),
(2 , 'Change brake fluid' ),
(3 , 'Change brake rotors' )
Declare #MechanicsLog Table
(ID int, ActivityID int, [Date] Date, Mechanic varchar(20), Comment varchar(50))
Insert into #MechanicsLog
values
(1 , 1 , '2019-06-27' , 'John' , 'Changed the oil filter' ),
(2 , 1 , '2019-06-26' , 'Sally' , 'No oil filters in stock.' ),
(3 , 2 , '2019-06-20' , 'Sally' , 'Brake fluid flushed.' )
Query
;With cte as
(select ActivityID, Max([Date]) [date] from #MechanicsLog ml
Group By ActivityID
)
Select al.ID, al.Activity, cte.[Date], Mechanic, Comment
from cte inner join #MechanicsLog ml
on cte.ActivityID = ml.ActivityID and cte.[date] = ml.[Date]
right join #ActivityList al on al.ID = ml.ActivityID
order by ID
If you add use the ROW_NUMBER function to add a sequence to each activity ID, you can then filter that to only get the most recent for each activity ID.
select ActivityID, Date, Mechanic, Comment
from
(
select *, ROW_NUMBER() OVER (PARTITION BY ActivityID order by Date desc) RowNumber
from MechanicsLog
) q1
where RowNumber = 1
This gives you the "MAX" record for each ActivityID but with the rest of the record, so you can join to the Activity List table if you want.
select
act.ActivityID, Max(log.[Date]) as [Date]
from
ActivityList act
inner join
MachineLog log on log.ActivityID = act.ActivityID
Group by
act.ActivityID

Update table column based on comparison of columns from 2 table (SQL)

I have the following tables.
Table 1
Id | Values | Counts
1 | rock | 0
2 | tina | 0
3 | alex | 0
Table 2
Id | Values
1 | rock
2 | alex
3 | alex
4 | rock
5 | rock
6 | tina
As you can see, table 1 contains Values as rock, tina and alex. These column will always have unique values. Counts column should check the count of 'rock' in Table 2 and update it in Counts column. for e.g. rock is shown 3 times in table 2. The counts for rock should be then 3.
Similarly for other values. Can someone pls let me know how can i achieve this using SQL. Here is how the final table should look like.
Table 1
Id | Values | Counts
1 | rock | 3
2 | tina | 1
3 | alex | 2
Any help is appreciated. I searched online and couldnot find a possible solution for this scenario.
You can generally use a JOIN between 2 tables to update Table1 with values from Table2 (or further if you are using bridge tables).
UPDATE t1
SET t1.dataColumn = t2.dataColumn
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.keyColumn = t2.keyColumn
However, when you are using Aggregate functions (such as Count, Sum)you must utilize a subquery for the second table and perform the JOIN to that subquery
UPDATE t1
SET t1.Counts = sb.Counts
FROM Table1 AS t1
INNER JOIN (
SELECT [values], Counts = Count([values])
FROM Table2
GROUP BY [values]
) AS sb
ON t1.[values] = sb.[values]
Running this on your tables gave me this:
SELECT * FROM Table1
id values counts
---- ------- -------
1 rock 3
2 tina 1
3 alex 2
One thing concerning your table design; I generally recommend not using reserved/special/key words when naming tables, columns, or other database objects. I also try to avoid using the generic name id because it can get confusing when you start linking tables to one another, even idTable1 can make things a lot easier
In SQL Server, using a correlated subquery:
update t1
set t1.Counts = (
select count(*)
from t2
where t2.[Values] = t1.[Values]
);
rextester demo: http://rextester.com/SBYNB72372
In MySQL, using a correlated subquery:
update t1
set t1.Counts = (
select count(*)
from t2
where t2.`Values` = t1.`Values`
);
rextester demo: http://rextester.com/DDDC21719
Although this sort of thing might be better calculated in a view instead of stored in the t1 table.
In SQL Server:
create view dbo.t1_with_counts as
select t1.Id, t1.[Values], count(t2.[Values]) as Counts
from t1
left join t2
on t1.[Values] = t2.[Values]
group by t1.Id, t1.[Values]
go
select *
from dbo.t1_with_counts;
In MySQL:
create view t1_with_counts as
select t1.Id, t1.`Values`, count(t2.`Values`) as Counts
from t1
left join t2
on t1.`Values` = t2.`Values`
group by t1.Id, t1.`Values`;
select *
from t1_with_counts;
I would question the wisdom of keeping track of a count in a table like that. That leads to poor relational database structure and management. Instead, I suggest you remove the count column from Table 1. Then, whenever you need to see the counts you use a view:
SELECT t1.ID, t1.VALUES, COUNT(t2.ID) AS VALUE_COUNT
FROM TABLE1 t1 LEFT JOIN TABLE2 t2 ON t1.VALUES = t2.VALUES
This results in a dynamically updated view of your data instead of a static view that has the potential for going stale without your realizing it.

Insert into Oracle SQL or Update if value already exist?

What I want is: If key exist in Oracle SQL Table → UPDATE, otherwise do a INSERT
After playing all day yesterday, I managed to get the INSERT part (query below), what I now need is the UPDATE part.
This is why I need it: I have a RadGridView (using Telerik and WPF). When a User clicks on Insert button a new Row is added and after the User hits Enter, the value is Inserted into the Database. But the user can also click on a available row in the RadGridView and update the values, so I need to update the values in my Database too (and not do a INSERT). And that is why I want a query that can perform a Udate or Insert.
Any help is appreciated, also if you have a better way of implementing the INSERT part, I would like to know about it :)
I am using Oracle SQL Developer (Windows 10).
ps. I tried some solutions I found on StackOverflow but could not manage to apply the solutions to my problem.
Table1
+-----------------------------------+------------+--------+
| ID | ORIGTERM | CODE |
+-----------------------------------+------------+--------+
| 126478 | Grass | TEST |
| 374628 | Flower | TEST |
| 128754 | Tree | TEST |
+-----------------------------------+------------+--------+
Table2
+-----------------------------------+------------+---------+
| ID |REPLACETERM |SYSCTLANG|
+-----------------------------------+------------+---------+
| 126478 | Gras | 3 |
| 374628 | Blume | 3 |
| 128754 | Baum | 3 |
+-----------------------------------+------------+---------+
I managed to got the INSERT query, it looks like this (example insert the word 'Plant'):
INSERT ALL
INTO Table1(origterm,code) VALUES (s_origterm,s_code)
INTO Table2(replaceterm) VALUES (s_replaceterm)
SELECT s_origterm, s_code, s_replaceterm
FROM (SELECT 'Plant' s_origterm, 'TEST' s_code, 'Pflanze' s_replaceterm FROM dual)
dual;
I must also update the ID of Table2 to be the same as the one from Table1:
UPDATE Table2 SET Table2.ID = (SELECT Table1.ID FROM Table1 WHERE origterm='Plant')
WHERE replaceterm='Pflanze';
Now I have a table that looks like this:
+-----------------------------------+------------+--------------+------+
| ID | ORIGTERM | REPLACETERM | CODE |
+-----------------------------------+------------+--------------+------+
| 126478 | Grass | Gras | TEST |
| 374628 | Flower | Blume | TEST |
| 128754 | Tree | Baum | TEST |
| 100000 | Plant | Pflanze | TEST |
+-----------------------------------+------------+--------------+------+
SELECT g.ID, origterm, replaceterm, code FROM Table1 g, Table2 ct WHERE g.ID = ct.ID;
Merge does not work with INSERT ALL. If you want to use merge, you should make from both table a view with instead of trigger and than use merge against the view. The whole logic will be inside the trigger.
EDIT: Merge does not work with such views
ORA-38106: MERGE bei Join View oder View mit INSTEAD OF-Trigger nicht unterstützt
You can make two merge statements (one for every table) or one for insert and one for update against view:
CREATE SEQUENCE MYDICT_SEQ START WITH 1 MAXVALUE 9999999999999999999999999999 MINVALUE 0;
CREATE VIEW mydict
AS
SELECT a.id, a.origterm, a.code, b.replaceterm, b.sysctlang
FROM table1 a LEFT OUTER JOIN table2 b ON a.id = b.id;
CREATE OR REPLACE TRIGGER mydict_io
INSTEAD OF INSERT OR UPDATE OR DELETE
ON mydict
FOR EACH ROW
DECLARE
cnt1 INTEGER := 0;
cnt2 INTEGER;
nid NUMBER;
BEGIN
IF INSERTING OR UPDATING THEN
IF :new.id IS NULL AND INSERTING THEN
nid := mydict_seq.NEXTVAL;
ELSE
nid := :new.id;
IF UPDATING THEN
nid := :old.id;
END IF;
SELECT COUNT (*)
INTO cnt1
FROM table1
WHERE id = nid;
END IF;
IF cnt1 = 0 THEN
INSERT INTO TABLE1 (ID, ORIGTERM, CODE)
VALUES (nID, :new.ORIGTERM, :new.CODE);
ELSIF cnt1 > 0 THEN
UPDATE TABLE1
SET ORIGTERM = :NEW.ORIGTERM, CODE = :NEW.CODE
WHERE id = nid;
END IF;
SELECT COUNT (*)
INTO cnt2
FROM table2
WHERE id = nid AND SYSCTLANG = :new.SYSCTLANG;
IF cnt2 = 0 THEN
INSERT INTO TABLE2 (ID, REPLACETERM, SYSCTLANG)
VALUES (nID, :new.REPLACETERM, :new.SYSCTLANG);
ELSE
UPDATE TABLE2
SET REPLACETERM = :new.REPLACETERM
WHERE id = nid AND SYSCTLANG = :new.SYSCTLANG;
END IF;
ELSIF DELETING THEN
DELETE FROM table2
WHERE id = :old.id AND SYSCTLANG = :old.SYSCTLANG;
SELECT COUNT (*)
INTO cnt2
FROM table2
WHERE id = nid;
IF cnt2 = 0 THEN
DELETE FROM table1
WHERE id = :old.id;
END IF;
END IF;
END;
DECLARE
nid NUMBER;
BEGIN
INSERT INTO mydict (ORIGTERM, CODE, REPLACETERM, SYSCTLANG)
VALUES ('Plant', 'TEST', 'Pflanze', 3);
nid := mydict_seq.currval;
UPDATE mydict
SET REPLACETERM = 'Fabrik'
WHERE id = nid;
UPDATE mydict
SET REPLACETERM = 'Usine', SYSCTLANG = 4
WHERE id = nid;
END;
The logic in the instead of trigger can be done better, but I leave this to you ;)
maybe it's too obvious but if you own the 'key' value probably this procedure will work:
DECLARE _flag AS INT = 0;
SELECT COUNT() INTO _flag FROM table1 WHERE ID = key;
IF _flag = 0 THEN
INSERT ...
ELSE
UPDATE ....
END IF;
adjust it to your own code needs and/or ORACLE SQL dialect.
A possible solution is to use the MERGE keyword, documented here:
http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9016.htm
Merge is basically an 'upsert' command, meaning that it will update row if exists or insert, if it doesn't.

How to select multiple Row and multiple field by one code with SQL

I want to select multiple row on a table. But I want to select fields every row too. Here is sample table :
---------------------
OrNo | Name | value
---------------------
1154 | Michael | 41
1154 | Rico | 24
1487 | Alex | 21
1487 | Leo | 27
I want to select based where "Orno" code which in the table is multiple. so I want to get every name and value on 1 of "OrNO".
For an example, I want to select where OrNO 1154. How to select all of name and value from that code? How to used sql data reader for read them?
Edit:
Based answered, I'm sorry, I want to execute on behind code, like sqldatareader with C#/VB.Net. I dont know how to execute them on behind code to store to varriable.
Thank you
SELECT *
FROM MyTable
WHERE OrNo IN
(
SELECT OrNo
FROM
(
SELECT OrNo, COUNT(*) AS RecordCount
FROM MyTable
GROUP BY OrNo
) A
WHERE RecordCount > 1
)
You want to return duplicate records per OrNo, so count per OrNo and only return records with a count > 1.
select orno, name, value
from
(
select orno, name, value, count(*) over (partition by orno) as cnt
from mytable
)
where cnt > 1
order by orno;
It's hard to understand your question.
Are you searching for the SQL Statement? If so, I would suggest:
SELECT *
FROM <TABLE_NAME>
WHERE OrNo IN
(
SELECT OrNo
FROM <TABLE_NAME>
GROUP BY OrNo
HAVING COUNT(*) > 1
)
Sorry, #jmcilhinney was faster here.
And one more, with ties
with t as (
select * from (values
(1154,'Michael',41),
(1154,'Rico',24),
(1199,'Mary',25),
(1487,'Alex',21),
(1487,'Leo',27)) t(OrNo, Name, value )
)
select top(1) with ties OrNo, Name, value
from t
order by
case count(*) over (partition by OrNo ) when 1 then 1 else 0 end

Stored Procedure for date ranges in a single column

Finding a solution to an issue in my project
I have stages associated with contracts. That is, a contract can be in either Active stage, Process stage or Terminated stage.
I need to get the no the days the contract was in each stage.
For example, if a contract C1 was in Active stage from 20/10/2013 to 22/10/2013, then in the Process stage from 22/10/2013 to 25/10/2013 and finally in Terminated stage from 25/10/2013 to 26/10/2013 and then again in Active from 26/10/2013 to 28/10/2013, then I should get as result
Active = 4days
Process = 3days
Terminated = 1day /likewise something
My table is created with these columns:
EntryId (primary key)
StageId (foreign key to Stage table)
ContractId (foreign key to contract table)
DateofStageChange
How to do this in SQL Server?
As asked pls find the table entries:
EntryID | Stage ID | Contract ID | DateChange
1 | A1 | C1 |20/10/2013
2 | P1 | C1 |22/10/2013
3 | T1 | C1 |25/10/2013
4 | A1 | C1 |26/10/2013
5 | P1 | C1 |28/10/2013
6 | T1 | C1 |Null(currently in this stage)
Need to use group by on Stage ID
it is important to check and make sure how data is populated in your table.Based on just your sample data and also note that if your entryid is not in sequence then you can create one sequence using row_number.
declare #t table(EntryId int identity(1,1), StageId int,ContractId varchar(10),DateofStageChange date)
insert into #t values
(1,'C1','2013-10-20'),(1,'C1','2013-10-22'),(2,'C1','2013-10-22'),(2,'C1','2013-10-25')
,(3,'C1','2013-10-25'),(3,'C1','2013-10-26'),(1,'C1','2013-10-26'),(1,'C1','2013-10-28')
Select StageId,sum([noOfDays]) [totalNofDays] from
(select a.StageId,a.ContractId,a.DateofStageChange [Fromdate],b.DateofStageChange [ToDate]
,datediff(day,a.DateofStageChange,b.DateofStageChange) [noOfDays]
from #t a
inner join #t b on a.StageId=b.StageId and b.EntryId-a.EntryId=1)t4
group by StageId
You can't with your current structure.
You can get the latest one by doing datediff(d, getdate(), DateOfStageChange)
but you don't have any history so you can't get previous status
This can be done in SQL with CTE.
You didnt provide your tablenames, so you'll need to change where I've indicated below, but it would look like this:
;WITH cte
AS (
SELECT
DateofStageChange, StageID, ContractID,
ROW_NUMBER() OVER (ORDER BY ContractID, StageId, DateofStageChange) AS RowNum
FROM
DateOfStageChangeTable //<==== Change this table name
)
SELECT
a.ContractId,
a.StageId,
Coalesce(sum(DATEDIFF(d ,b.DateofStageChange,a.DateofStageChange)), 'CurrentState`) as Days
FROM
cte AS A
LEFT OUTER JOIN
cte AS B
ON A.RowNum = B.RowNum + 1 and a.StageId = b.StageId and a.ContractId = b.ContractId
group by a.StageId, a.ContractId
This really is just a self join that creates a row number on a table, orders the table by StageID and date and then joins to itself. The first date on the first row of the stage id and date, joins to the second date on the second row, then the daterange is calculated in days.
This assumes that you only have 2 dates for each stage, if you have several, you would just need to do a min and max on the cte table.
EDIT:
Based on your sample data, the above query should work well. Let me know if you get any syntax errors and I'll fix them.
I added a coalesce to indicate the state they are currently in.

Categories