Merge Defaut and User Adjusted Data - sql

I have a table:
Type (PK) Year (PK) Value
Default 2000 1
Default 2001 2
UserFooAdjusted 2001 3
UserBarAdjusted 2001 4
What is the fastest SQL query that returns distinct years and if there are two rows with the same year then the user adjusted value is returned? There are multiple users. The query returns data for one user. Example result:
Year Value
2000 1
2001 3
I've thougt about A UNION B but how do I always keep the duplicate from B? Maybe a better solution would be to divide the current table into two tables: one would contain default values and the other would contain user adjusted vaules?

Assuming that there are only two types: Default and UserAdjusted, you can use Common Table Expression and Window Functions, in sql server.
WITH recordList
AS
(
SELECT YEAR, VALUE,
ROW_NUMBER() OVER (PARTITION BY YEAR
ORDER BY TYPE DESC) rn
FROM tableName
)
SELECT YEAR, VALUE
FROM recordList
WHERE rn = 1
SQLFiddle Demo

Related

Group BY Statement error to get unique records

I am new to SQL Server, used to work with MYSQL and trying to get the records from a table using Group By.
The table structure is given below:
SELECT S1.ID,S1.Template_ID,S1.Assigned_By,S1.Assignees,S1.Active FROM "Schedule" AS S1;
Output:
ID Template_ID Assigned_By Assignees Active
2 25 1 3 1
3 25 5 6 1
6 26 5 6 1
I need to get the values of all columns using the Group By statement below
SELECT Template_ID FROM "Schedule" WHERE "Assignees" IN(6, 3) GROUP BY "Template_ID";
Output:
Template_ID
25
26
I tried the following code to fetch the table using Group By, but it's fetching all the rows.
SELECT S1.ID,S1.Template_ID,S1.Assigned_By,S1.Assignees,S1.Active FROM "Schedule" AS S1 INNER JOIN(SELECT Template_ID FROM "Schedule" WHERE "Assignees" IN(6, 3) GROUP BY "Template_ID") AS S2 ON S2.Template_ID=S1.Template_ID
My Output Should be like,
ID Template_ID Assigned_By Assignees Active
2 25 1 3 1
6 26 5 6 1
I was wondering whether I can get ID of the column as well? I use the ID for editing the records in the web.
The query doesn't work as expected in MySQL either, except by accident.
Nonaggregated columns in MySQL aren't part of the SQL standard and not even allowed in MySQL 5.7 and later unless the default value of the ONLY_FULL_GROUP_BY mode is changed.
In earlier versions the result is non-deterministic.
The server is free to choose any value from each group, so unless they are the same, the values chosen are nondeterministic. Furthermore, the selection of values from each group cannot be influenced by adding an ORDER BY clause.
This means there's was no way to know what rows will be returned this query :
SELECT S1.ID,S1.Template_ID,S1.Assigned_By,S1.Assignees,S1.Active
FROM "Schedule" AS S1
GROUP BY Template_ID;
To get deterministic results you'd need a way to rank rows with the ranking functions introduced in MySQL 8, like ROW_NUMBER(). These are already available in SQL Server since SQL Server 2012 at least. The syntax is the same for both databases :
WITH ranked as AS
(
SELECT
ID,Template_ID,Assigned_By,Assignees Active,
ROW_NUMBER(PARTITION BY Template_ID Order BY ID)
FROM Scheduled
WHERE Assignees IN(6, 3)
)
SELECT ID,Template_ID,Assigned_By,Assignees Active
FROM ranked
Where RN=1
PARTITION BY Template_ID splits the result rows based on their Template_ID value into separate partitions. Within that partition, the rows are ordered based on the ORDER BY clause. Finally, ROW_NUMBER calculates a row number for each ordered partition row.

duplicates to be removed sql

I have in database records
My sql:
SELECT
DISTINCT name, date(mod_wr)
FROM
test.object_stg
WHERE
ir = '4552724'
GROUP BY
name, date(mod_wr)
ORDER BY name
The last record is the same as the last but one. It has only a different date.
Is it possible to somehow query to return all records where there has been a change in the "name" column?
For record 4 and 5 there is the same name, only a different date. I would like it to return only a record of 4 and 5, because there was no change.
If you don't want to remove rows where values are resused. E.g. your line #2, you can use LAG() and then only include rows where the value is different to the previous. E.g.
select name, date(mod_wr) from
(
SELECT
name, mod_wr, lag(name) over(order by mod_wr) as prev_name
FROM
test.object_stg
WHERE
ir = '4552724'
)
WHERE prev_name IS NULL OR name <> prev_name
From your sample data, you have 3 distinct names. However, you cannot use distinct in your select statement because it applies to every field listed and none of the dates would provide an exact match.
However, you can use a group by statement in order to collate your titles together.
// MySQL 5.6 Statement
select name, date(mod_wr) from object_stg group by name;
// MSSQL 2017 Statement
select name, max(mod_wr) from object_stg group by name;
Both statements return 3 lines with just the BMW, 1.0 GL and 1.0 GLS showing with a single date.
SQL Fiddle

How to distinguish rows in a database table on the basis of two or more columns while returning all columns in sql server

I want to distinguish Rows on the basis of two or more columns value of the same table at the same time returns all columns from the table.
Ex: I have this table
DB Table
I want my result to be displayed as: filter on the basis of type and Number only. As in abover table type and Number for first and second Row is same so it should be suppressed in result.
txn item Discrip Category type Number Mode
60 2 Loyalty L 6174 XXXXXXX1390 0
60 4 Visa C 1600 XXXXXXXXXXXX4108 1
I have tried with sub query but yet unsuccessful. Please suggest what to try.
Thanks
You can do what you want with row_number():
select t.*
from (select t.*,
row_number() over (partition by type, number order by item) as seqnum
from t
) t
where seqnum = 1;

Multiple Distinct Values with SUM

i have a table which Data is like
userID name amount Date
1 mark 20 22-10
1 mark 30 22-10
2 kane 50 22-12
2 kane 60 22-12
3 mike 60 22-10
Date is Unique with combination of userID + Username + Date
but as its more then 100k records there maybe duplicate date records but wither other user ids and names not with
now i want Output like
userID name amount Date
1 mark 50 22-10
2 kane 110 22-12
3 mike 60 22-10
if i try group By with id,name,sum(amount),date it returns multiple rows and answer incorrect
i have tried various combination of distict and SUM etc etc but not succeeded
any Solution
Thanks
You typically use a GROUP BY to aggregate one or more fields by one or more other fields.
SELECT userID, Name, SUM(amount), MIN(date)
FROM YourTable
GROUP BY
userID, Name
From MSDN: Aggregate functions
Aggregate functions perform a calculation on a set of values and
return a single value. With the exception of COUNT, aggregate
functions ignore null values. Aggregate functions are often used with
the GROUP BY clause of the SELECT statement.
some typical aggregate functions are
SUM
MIN
AVG
...
From MSDN: GROUP BY
Groups a selected set of rows into a set of summary rows by the values
of one or more columns or expressions in SQL Server 2008 R2. One row
is returned for each group. Aggregate functions in the SELECT clause
list provide information about each group instead of
individual rows.
select
userId, name, sum(amount) as amount
from
table
group by
userId, name
You don't want DISTINCT here, but rather GROUP BY with the aggregate SUM()
SELECT
userID,
name,
SUM(amount) AS amount
FROM tbl
GROUP BY userID, name

Getting the min() of a count(*) column

I have a table called Vehicle_Location containing the columns (and more):
ID NUMBER(10)
SEQUENCE_NUMBER NUMBER(10)
TIME DATE
and I'm trying to get the min/max/avg number of records per day per id.
So far, I have
select id, to_char(time), count(*) as c
from vehicle_location
group by id, to_char(time), min having id = 16
which gives me:
ID TO_CHAR(TIME) COUNT(*)
---------------------- ------------- ----------------------
16 11-05-31 159
16 11-05-23 127
16 11-06-03 56
So I'd like to get the min/max/avg of the count(*) column. I am using Oracle as my RDBMS.
I don't have an oracle station to test on but you should be able to just wrap the aggregator around your SELECT as a subquery/derived table/inline view
So it would be (UNTESTED!!)
SELECT
AVG(s.c)
, MIN(s.c)
, MAX(s.c)
, s.ID
FROM
--Note this is just your query
(select id, to_char(time), count(*) as c from vehicle_location group by id, to_char(time), min having id = 16) as s
GROUP BY s.ID
Here's some reading on it:
http://www.devshed.com/c/a/Oracle/Inserting-SubQueries-in-SELECT-Statements-in-Oracle/3/
EDIT: Though normally it is a bad idea to select both the MIN and MAX in a single query.
EDIT2: The min/max issue is related to how some RDBMS (including oracle) handle aggregations on indexed columns. It may not affect this particular query but the premise is that it's easy to use the index to find either the MIN or the MAX but not both at the same time because any index may not be used effectively.
Here's some reading on it:
http://momendba.blogspot.com/2008/07/min-and-max-functions-in-single-query.html