Selecting all rows in a master table and summing columns in multiple detail tables - sql

I have a master table (Project List) along with several sub tables that are joined on one common field (RecNum). I need to get totals for all of the sub tables, by column and am not sure how to do it. This is a sample of the table design. There are more columns in each table (I need to pull * from "Project List") but I'm showing a sampling of the column names and values to get an idea of what to do.
Project List
| RecNum | Project Description |
| 6 | Sample description |
| 7 | Another sample |
WeekA
| RecNum | UserName | Day1Reg | Day1OT | Day2Reg | Day2OT | Day3Reg | Day3OT |
| 6 | JustMe | 1 | 2 | 3 | 4 | 5 | 6 |
| 6 | NotMe | 1 | 2 | 3 | 4 | 5 | 6 |
| 7 | JustMe | | | | | | |
| 7 | NotMe | | | | | | |
WeekB
| RecNum | UserName | Day1Reg | Day1OT | Day2Reg | Day2OT | Day3Reg | Day3OT |
| 6 | JustMe | 7 | 8 | 1 | 2 | 3 | 4 |
| 6 | NotMe | 7 | 8 | 1 | 2 | 3 | 4 |
| 7 | JustMe | | | | | | |
| 7 | NotMe | | | | | | |
So the first query should return the complete totals for both users, like this:
| RecNum | Project Description | sumReg | sumOT |
| 6 | Sample description | 40 | 52 |
| 7 | Another sample | 0 | 0 |
The second query should return the totals for just a specified user, (WHERE UserName = 'JustMe') like this:
| RecNum | Project Description | sumReg | sumOT |
| 6 | Sample description | 20 | 26 |
| 7 | Another sample | 0 | 0 |

Multiple parallel tables with the same structure is usually a sign of poor database design. The data should really be all in one table, with additional columns specifying the week.
You can, however, use union all to bring the data together. The following is an example of a query:
select pl.recNum, pl.ProjectDescription,
sum(Day1Reg + Day2Reg + Day3Reg) as reg,
sum(Day1OT + Day2OT + Day3OT) as ot
from ProjectList pl join
(select * from weekA union all
select * from weekB
) w
on pl.recNum = w.recNum
group by l.recNum, pl.ProjectDescription,;
In practice, you should use select * with union all. You should list the columns out explicitly. You can add appropraite where clauses or conditional aggregation to get the results you want in any particular case.

Related

how to insert into sql table additional values from second table if primary ids both start with 1?

the supply table:
supply_id | title | author | price | amount |
+-----------+----------------+------------------+--------+--------+
| 1 | Лирика | Пастернак Б.Л. | 518.99 | 2 |
| 2 | Черный человек | Есенин С.А. | 570.20 | 6 |
| 3 | Белая гвардия | Булгаков М.А. | 540.50 | 7 |
| 4 | Идиот | Достоевский Ф.М. | 360.80 | 3
I am trying to insert into book , all the values from supply:
+---------+-----------------------+------------------+--------+--------+
| book_id | title | author | price | amount |
+---------+-----------------------+------------------+--------+--------+
| 1 | Мастер и Маргарита | Булгаков М.А. | 670.99 | 3 |
| 2 | Белая гвардия | Булгаков М.А. | 540.50 | 5 |
| 3 | Идиот | Достоевский Ф.М. | 460.00 | 10 |
| 4 | Братья Карамазовы | Достоевский Ф.М. | 799.01 | 2 |
| 5 | Стихотворения и поэмы | Есенин С.А. | 650.00 | 15 |
+---------+-----------------------+------------------+--------+--------+
insert into book(title,author,price,amount)
select * from supply;
the primary ids conflict with each other - both tables start with id '1'
ERROR 1136: Column count doesn't match value count at row 1
Your columns in insert and select mismatches. You need to give explicit names of the columns instead of * in SELECT clause.
Try this:
insert into book(title,author,price,amount)
select title,author,price,amount from supply;

How to name child elements of a parent element by value? SQL server

Please, tell me an example how to mark all the child nodes to the parent id. Only need to mark those branches whose parent has the value "need" (see example image). Using a recursive query, it is not possible to rename all the children of a particular parent...
Initial data:
+-----+----------+----------+
| id | parentid | selector |
+-----+----------+----------+
| 1 | | |
| 2 | 1 | |
| 3 | 1 | need |
| 4 | 2 | |
| 5 | 2 | need |
| 6 | 3 | |
| 7 | 5 | |
| 8 | 5 | |
| 9 | 6 | |
+-----+----------+----------+
Need data:
+-----+----------+----------+----------------+
| id | parentid | selector | parentSelector |
+-----+----------+----------+----------------+
| 1 | null | | null |
| 2 | 1 | | null |
| 3 | 1 | need | 3 |
| 4 | 2 | | null |
| 5 | 2 | need | 5 |
| 6 | 3 | | 3 |
| 7 | 5 | | 5 |
| 8 | 5 | | 5 |
| 9 | 6 | | 3 |
+-----+----------+----------+----------------+
The task is to make the grouping by those elements whose parent has the value "need". I think, I should create a column with a mark, as in the example in the table above, or are there any other options?
I use SQL Server 2012
I dont't know if it work on Sql server 2012, but i found this microsoft, i think is what you want, to make the parentSelector with condition, I use CASE (Transact-SQL).
This is another example: stackoverflow question

Row Level Security with multiple users for one row

I'm trying to implement Row Level Security in SQL Server 2016.
The problem is, I can have multiple users that should have read permissions over given rows, and when I write some complex condition in the predicate the performance gets like very very very bad.
I tried to keep all usernames in one column of the table and in the predicate to search through them for the SYSTEM_USER with % LIKE % but performance is low.
Example of the values in the Usernames column in my controlled table for one row:
domain\john.wick;domain\red.eagle;domain\spartak.something....
Here is my function:
CREATE FUNCTION fn_securitypredicate(#Usernames AS nvarchar(4000))
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
SELECT 1 as Result
WHERE #Usernames LIKE '%' + SYSTEM_USER + '%'
With this execution time from 2 sec became 50 sec. Any suggestions for improvement.
CREATE SECURITY POLICY [Policy]
ADD FILTER PREDICATE [fn_securitypredicate]([Usernames])
ON [dbo].[Products];
This is the solution I came up with for my previous team.
This requires a a users table, a users permissions table as well as a permission column on your controlled table. It should also have a user group and user group permissions table to scale with users.
users user_permissions controlled_table
+-----------+---------+ +---------+---------------+ +---------------+------+------+
| user_name | user_id | | user_id | permission_id | | permission_id | pk_1 | pk_2 |
+-----------+---------+ +---------+---------------+ +---------------+------+------+
| admin | 1 | | 1 | 0 | | 2 | 1 | 1 |
| user1 | 2 | | 2 | 1 | | 2 | 1 | 2 |
| user2 | 3 | | 2 | 2 | | 3 | 1 | 3 |
| user3 | 4 | | 2 | 3 | | 4 | 2 | 1 |
| | | | 2 | 4 | | 3 | 2 | 2 |
| | | | 3 | 1 | | 1 | 2 | 3 |
| | | | 3 | 2 | | 1 | 3 | 1 |
| | | | 4 | 2 | | 5 | 3 | 2 |
| | | | 4 | 3 | | 4 | 3 | 3 |
| | | | 4 | 4 | | 2 | 4 | 1 |
| | | | | | | 3 | 4 | 2 |
| | | | | | | 3 | 4 | 3 |
+-----------+---------+ +---------+---------------+ +---------------+------+------+
For performance, you will want to add the permission_id to whatever index you were using to search the controlled table. This will allow you to join permissions on the index while searching on the remaining columns. You should view the execution plan for specific details on your indexes.

Showing data from another table if it exists

I am having a hard time trying to get the correct data out of my DB.
I have a couple of tables:
events_template laser_events
| id | something | | id | extid | added |
================== ===========================
| 1 | something | | 1 | 7 | added |
| 2 | something | | 2 | 4 | added |
| 3 | something | | 3 | 2 | added |
| 4 | something | | 4 | 1 | added |
| 5 | something | | 5 | 9 | added |
| 6 | something | | 6 | 3 | added |
| 7 | something |
| 8 | something |
| 9 | something |
| 10 | something |
| 11 | something |
| 12 | something |
| 13 | something |
| 14 | something |
What I am trying to do is get some output that will show me the results of both tables together linked by id and extid, but still show the results from events_template even if there isn't a matching laser_events row.
I've tried something like
SELECT
id,
extid
FROM
events_template,
laser_events
WHERE
events_template.id = laser_events.ext_id;
But that doesn't show me the events_template rows if there isn't a matching laser_events row.
Any help would be appreciated!
You have to use LEFT JOIN:
SELECT e.id, l.ext_id
FROM events_template e
LEFT JOIN laser_events l ON e.id = l.ext_id;

Rails 3 - complex query with joins and counts, possible subqueries?

Ok, so i have a bit of a complex query i am trying to come up with in my rails application. I have four tables: Clients, Projects, Invoices, Invoice_Line_Items. I am trying to get certain bits of data from all of those tables and display it in a "reports" type view in my application. This is what the structures look like for the four tables:
Clients
| id | name | archive |
----------------------------------------
| 1 | Client 1 | 0 |
| 2 | Client 2 | 0 |
Projects
| id | client_id | name | archive |
------------------------------------------------------
| 1 | 1 | Project 1 | 0 |
| 2 | 1 | Project 2 | 1 |
| 3 | 2 | Project 3 | 0 |
| 4 | 2 | Project 4 | 1 |
Invoices
| id | client_id | project_id | name | archive |
----------------------------------------------------------------------
| 1 | 1 | 1 | Invoice 1 | 0 |
| 2 | 1 | 1 | Invoice 2 | 0 |
| 3 | 1 | 2 | Invoice 3 | 1 |
| 4 | 1 | 2 | Invoice 4 | 1 |
| 5 | 2 | 3 | Invoice 5 | 0 |
| 6 | 2 | 3 | Invoice 6 | 0 |
| 7 | 2 | 4 | Invoice 7 | 1 |
| 8 | 2 | 4 | Invoice 8 | 1 |
Invoice_Line_Items
| id | invoice_id | name | amount_due |
---------------------------------------------------------
| 1 | 1 | Item 1 | 500 |
| 2 | 1 | Item 2 | 500 |
| 3 | 2 | Item 3 | 500 |
| 4 | 2 | Item 4 | 500 |
| 5 | 3 | Item 5 | 500 |
| 6 | 3 | Item 6 | 500 |
| 7 | 4 | Item 7 | 500 |
| 8 | 4 | Item 8 | 500 |
| 9 | 5 | Item 9 | 500 |
| 10 | 5 | Item 10 | 500 |
| 11 | 6 | Item 11 | 500 |
| 12 | 6 | Item 12 | 500 |
| 13 | 7 | Item 13 | 500 |
| 14 | 7 | Item 14 | 500 |
| 15 | 8 | Item 15 | 500 |
| 16 | 8 | Item 16 | 500 |
Ok, hope those diagrams make sense enough. What i am looking for as a result set is this (example data set taken from above example data):
| clients.name | current_projects | archived_projects | total_amount_due | total_amount_paid |
-----------------------------------------------------------------------------------------------------------
| Client 1 | 1 | 1 | 2000 | 2000 |
| Client 2 | 1 | 1 | 2000 | 2000 |
Ok, so here's what's going on there:
Getting all non-archived clients
Getting a count of all non-archived projects
Getting a count of all archived projects
Getting a total_amount_due from the invoice_line_items table that is a sum of all of the non-archived invoices
Getting a total_amount_paid from the invoice_line_items table that is a sum of all of the archived invoices
I am relatively new to Rails and this is a fairly complex query (at least in my head). Please let me know if there is a simpler solution that i am overlooking or if i am just over complicating it. If i need to do multiple queries in my controller that's fine, i was just wanting to see if i could get away with one sql call. I'm pretty sure i can do this pretty easily with some subqueries but i'm not sure how to write those in the controller in Rails.
Thanks for any help or direction you can provide and if this question is just outrageous or whatever just let me know and i'll delete it and go search the Googles more (have tried already to no avail).
Ok, well i ended up figuring out a solution myself. Not quite sure it's the best solution....feels heavy and messing but i just created quite a few objects in the controller to get the sql statements i needed to pull the data from the database. I basically have one object for each column (column, not each row). Let me know if anyone can figure out a better solution.